Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

findByIdAndUpdate should not work with undefined id #10964

Closed
fromi opened this issue Nov 9, 2021 · 5 comments · Fixed by #11079
Closed

findByIdAndUpdate should not work with undefined id #10964

fromi opened this issue Nov 9, 2021 · 5 comments · Fixed by #11079
Labels
developer-experience This issue improves error messages, debugging, or reporting

Comments

@fromi
Copy link

fromi commented Nov 9, 2021

Do you want to request a feature or report a bug?
Neither a feature or a bug, but an improvement for the API

What is the current behavior?
Actually, findByIdAndUpdate(id, ...) is equivalent to findOneAndUpdate({ _id: id }, ...), as stated by the documentation.
That's working accordingly, however this is not the logically expected behavior when the id is undefined:
findOneAndUpdate({ _id: undefined }, ...) => this form, understandably, should update the first entry.
findByIdAndUpdate(undefined, ...) => this form however should fail.

What is the expected behavior?
I expect an argument error when using findByIdAndUpdate with an undefined id.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Mongoose v5.13.8

@IslandRhythms
Copy link
Collaborator

When you call findByIdAndUpdate() its expecting an _id, so you can just pass that in without having to do the {_id: obj._id}. As a result, when you pass in undefined, it turns undefined into that structure like so: {_id: undefined}

@fromi
Copy link
Author

fromi commented Nov 9, 2021

Hi @IslandRhythms, I understand that, I am just saying that it is an unexpected behavior, which in my case made a bug much harder to track and to understand than if the id parameter was mandatory (with control checking). I am not saying that there is a bug, I am suggesting an improvement for the API.

@IslandRhythms
Copy link
Collaborator

So something that should be mentioned in the docs?

@fromi
Copy link
Author

fromi commented Nov 10, 2021

Yes, and also a minor change in the code:

  • Inside the code, add something like that in the function:
if (id === undefined) throw new Error('Illegal argument: id cannot be undefined)
  • Inside the doc, the error throwing can be documented too.

@IslandRhythms IslandRhythms added the developer-experience This issue improves error messages, debugging, or reporting label Nov 10, 2021
@vkarpov15 vkarpov15 added this to the 6.x Unprioritized milestone Nov 17, 2021
@vkarpov15 vkarpov15 reopened this Jan 6, 2022
@vkarpov15 vkarpov15 modified the milestones: Parking Lot, 7.0 Oct 5, 2022
@vkarpov15
Copy link
Collaborator

We took a closer look, and realistically I don't think we should make this particular change. We would have to throw an error in findByIdAndUpdate(), findById(), etc. But then that would break chaining, like Model.findByIdAndUpdate(undefined, { bar: 'baz' }).findByIdAndUpdate('foo');. Admittedly, this is a strange pattern, but it illustrates the fundamental issue with eagerly validating arguments in some cases, when Mongoose relies on lazy validation for queries in all other cases (we don't run query validation until the query actually runs).

If you need Mongoose to throw an error if filtering by an undefined id, you can use middleware as follows:

schema.pre(/.*/, { query: true }, function() {
  if (this.getFilter() && this.getFilter()._id === undefined) {
    throw new Error('Cannot filter by _id === undefined');
  }
});

Below is a working example:

'use strict';

const mongoose = require('mongoose');

const schema = mongoose.Schema({ name: String });

schema.pre(/.*/, { query: true }, function() {
  if (this.getFilter() && this.getFilter()._id === undefined) {
    throw new Error('Cannot filter by _id === undefined');
  }
});

run().catch(err => console.log(err));

async function run() {
  await mongoose.connect('mongodb://127.0.0.1/gh10964');
  const Test = mongoose.model('Test', schema);

  // Throws "Error: Cannot filter by _id === undefined"
  await Test.findByIdAndUpdate(undefined, { name: 'foo' });
  console.log('Done');
}

@vkarpov15 vkarpov15 removed this from the 7.0 milestone Feb 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
developer-experience This issue improves error messages, debugging, or reporting
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants