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

Projection with '+' not including field (since v7.1.1) #13773

Closed
2 tasks done
draperunner opened this issue Aug 23, 2023 · 4 comments · Fixed by #13932
Closed
2 tasks done

Projection with '+' not including field (since v7.1.1) #13773

draperunner opened this issue Aug 23, 2023 · 4 comments · Fixed by #13932
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@draperunner
Copy link

draperunner commented Aug 23, 2023

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

7.1.1

Node.js version

16.x, 18.x

MongoDB server version

4.4

Typescript version (if applicable)

No response

Description

This issue is very similar to this: #13340

7.1.1 is the first version that is bad. I have tested that 7.1.0 works, and that the latest version (7.4.4) also fails.

I have a Schema where one sub-document is not selected by default (select: false in schema definition). I have queries that needs this sub-document and therefore select it explicitly with the "+" syntax like so: .select("+myField").
The problem is that this field is not returned although being explicitly selected.

Note that one difference from #13340 is that now the other fields are included, just not the one that is selected. In #13340 only the _id was returned – no other fields.

Steps to Reproduce

This can be reproduced by running the following code with mongoose >= 7.1.1. See that age is not returned.

If you use mongoose 7.1.0, age is included in the response as expected.

const mongoose = require('mongoose');

async function main() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');

  const kittySchema = new mongoose.Schema({
      name: String,
      age: {
        select: false,
        type: Number
      }
    });

  const Kitten = mongoose.model('Kitten', kittySchema);
  const silence = new Kitten({ name: 'Silence', age: 2 });
  await silence.save()

  const updated = await Kitten.findByIdAndUpdate(silence._id, { age: 3 })
    .select("+age")

  console.log("UPDATED", updated) // <-- Returns _id, name and __v, but not age!
}

main()

Result from the console.log using mongoose 7.1.1:

UPDATED {
  _id: new ObjectId("64e674ea250a3fbd6b986c1c"),
  name: 'Silence',
  __v: 0
}

Result from the console.log using mongoose 7.1.0:

UPDATED {
  _id: new ObjectId("64e676bfd40527d1db7d3166"),
  name: 'Silence',
  age: 2,
  __v: 0
}

Expected Behavior

When using .select('+someField'), someField should be included in the response.

@draperunner
Copy link
Author

draperunner commented Aug 23, 2023

Something also happened in v7.2.1 with find queries. age is returned as expected in 7.2.0, but is broken in 7.2.1:

Run the following code with v7.2.1 to see that age is not included:

const mongoose = require("mongoose");

async function main() {
  await mongoose.connect("mongodb://127.0.0.1:27017/test");

  const kittySchema = new mongoose.Schema({
    name: String,
    age: {
      select: false,
      type: Number,
    },
  });

  const Kitten = mongoose.model("Kitten", kittySchema);
  const silence = new Kitten({ name: "Silence", age: 2 });
  await silence.save();

  const cursor = Kitten.find().select("+age").cursor();

  for await (const kitten of cursor) {
    console.log(kitten);
  }

  mongoose.disconnect();
}

main();

This outputs:

{
  _id: new ObjectId("64e67ba65da08a10deff42a2"),
  name: 'Silence',
  __v: 0
}

While running with version 7.2.0 gives:

{
  _id: new ObjectId("64e67c3191569b0402e87d32"),
  name: 'Silence',
  age: 2,
  __v: 0
}

@vkarpov15 vkarpov15 added this to the 7.5.1 milestone Aug 25, 2023
@vkarpov15 vkarpov15 added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label Aug 25, 2023
@IslandRhythms IslandRhythms added can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Aug 29, 2023
@IslandRhythms
Copy link
Collaborator

Mongoose 7.4.5 does not have this issue. Unable to reproduce.

const mongoose = require('mongoose');

async function main() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');

  const kittySchema = new mongoose.Schema({
      name: String,
      age: {
        select: false,
        type: Number
      }
    });

  const Kitten = mongoose.model('Kitten', kittySchema);
  const silence = new Kitten({ name: 'Silence', age: 2 });
  await silence.save()

  const updated = await Kitten.findByIdAndUpdate(silence._id, { age: 3 })
    .select("+age")

  console.log("UPDATED", updated) // <-- Returns _id, name and __v, but not age!
}

main()
UPDATED {
  _id: new ObjectId("64ee519258a712e851a47d50"),
  name: 'Silence',
  age: 2,
  __v: 0
}

@vkarpov15 vkarpov15 removed this from the 7.5.1 milestone Sep 1, 2023
@github-actions
Copy link

This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days

@github-actions github-actions bot added the Stale label Sep 16, 2023
@draperunner
Copy link
Author

I have tested again, and yes, findByIdAndUpdate now works with v7.4.5.

But not using cursor as I explained in my first comment!

The following code:

const mongoose = require("mongoose");

async function main() {
  await mongoose.connect("mongodb://127.0.0.1:27017/test");

  const kittySchema = new mongoose.Schema({
    name: String,
    age: {
      select: false,
      type: Number,
    },
  });

  const Kitten = mongoose.model("Kitten", kittySchema);
  const silence = new Kitten({ name: "Silence", age: 2 });
  await silence.save();

  const cursor = Kitten.find().select("+age").cursor();

  for await (const kitten of cursor) {
    console.log(kitten);
  }

  mongoose.disconnect();
}

main();

Returns

{
  _id: new ObjectId("6505714454789b1a5e9e3d62"),
  name: 'Silence',
  __v: 0
}

But the expected result is

{
  _id: new ObjectId("6505714454789b1a5e9e3d62"),
  name: 'Silence',
  age: 2,
  __v: 0
}

@github-actions github-actions bot removed the Stale label Sep 17, 2023
@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. labels Sep 26, 2023
@vkarpov15 vkarpov15 added this to the 7.5.4 milestone Sep 26, 2023
@vkarpov15 vkarpov15 added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Oct 3, 2023
vkarpov15 added a commit that referenced this issue Oct 4, 2023
…de `select: false` fields with `+` projection using cursors

Fix #13773
vkarpov15 added a commit that referenced this issue Oct 4, 2023
fix(QueryCursor): avoid double-applying schema paths so you can include `select: false` fields with `+` projection using cursors
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
3 participants