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

Populate with select on nested field returns extra sub-field of array type. #13003

Closed
2 tasks done
mattinbits opened this issue Feb 6, 2023 · 1 comment
Closed
2 tasks done
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@mattinbits
Copy link

Prerequisites

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

Mongoose version

6.9.0

Node.js version

16.13.1

MongoDB server version

6.0.3

Typescript version (if applicable)

4.1.3

Description

A parent schema contains a reference to a child schema. The child schema contains a nested field, with a string property and an array property. When populating a parent and selecting the nested string property, the array property is also included, with empty contents.

Steps to Reproduce

Example code:

import mongoose from "mongoose";

export const ParentSchema = new mongoose.Schema({
  title: String,
  childId: { type: mongoose.Schema.Types.ObjectId, ref: "Child" }
});

export const Parent = mongoose.model("Parent", ParentSchema);

const childSchema = new mongoose.Schema({
  name: String,
  properties: { foo: String, bar: [{ baz: String, qux: Boolean }] }
});

export const Child = mongoose.model("Child", childSchema);

async function run() {
  const child = await Child.create({ name: "c1", properties: { foo: "foo1", bar: [] } });

  const parent = await Parent.create({ title: "p1", childId: child._id });

  const res = await Parent.findOne({ title: "p1" }).populate({
    path: "childId",
    model: Child,
    select: { "properties.foo": 1 }
  });
  return res;
}

mongoose
  .connect("mongodb://localhost:27017/test")
  .then((_) => run())
  .then((res) => console.log(JSON.stringify(res)));

This prints:

{
  "_id": "63e16b1747e00097cf9a5957",
  "title": "p1",
  "childId": {
    "properties": { "foo": "foo1", "bar": [] },
    "_id": "63e16b1747e00097cf9a5955"
  },
  "__v": 0
}

Note that the bar field is included, unexpectedly. If I populate the bar array in the child document, such as:

const child = await Child.create(
    {
        name: "c1", 
        properties: { foo: "foo1", bar: [{baz: "quk", qux: true}] } 
    });

Then I still get an empty bar array in the populated parent document.

I don't encounter the same problem when bar is a simple string property instead of an array of objects, e.g.:

properties: { foo: String, bar: String }

Using the original example with Mongoose 5.11.5 I get the expected result:

{
  "_id": "63e16b1747e00097cf9a5957",
  "title": "p1",
  "childId": {
    "properties": { "foo": "foo1" },
    "_id": "63e16b1747e00097cf9a5955"
  },
  "__v": 0
}

Expected Behavior

The populated Parent document contains only the properties.foo field, similar to with mongoose 5.x.

@IslandRhythms IslandRhythms added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Feb 8, 2023
@IslandRhythms
Copy link
Collaborator

const mongoose = require('mongoose');

const ParentSchema = new mongoose.Schema({
  title: String,
  childId: { type: mongoose.Schema.Types.ObjectId, ref: "Child" }
});

const Parent = mongoose.model("Parent", ParentSchema);

const childSchema = new mongoose.Schema({
  name: String,
  properties: { foo: String, bar: [{ baz: String, qux: Boolean }] }
});

const Child = mongoose.model("Child", childSchema);

async function run() {
  await mongoose.connect('mongodb://localhost:27017');
  await mongoose.connection.dropDatabase();
  const child = await Child.create({ name: "c1", properties: { foo: "foo1", bar: [] } });

  const parent = await Parent.create({ title: "p1", childId: child._id });

  const res = await Parent.findOne({ title: "p1" }).populate({
    path: "childId",
    model: Child,
    select: { "properties.foo": 1 }
  });
  console.log(res);
}

run();

@vkarpov15 vkarpov15 modified the milestones: 6.9.2, 6.9.3 Feb 12, 2023
@vkarpov15 vkarpov15 modified the milestones: 6.9.3, 6.9.5 Feb 21, 2023
vkarpov15 added a commit that referenced this issue Mar 6, 2023
vkarpov15 added a commit that referenced this issue Mar 6, 2023
fix(document): avoid setting array default if document array projected out by sibling projection
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
Development

No branches or pull requests

3 participants