mongodb-js / mongoose-autopopulate

Always populate() certain fields in your mongoose schemas
Apache License 2.0
221 stars 36 forks source link

Subdocuments and Nested Schemas don't have their children auto populated if they are the second+ entry added to an array #77

Closed Ozay34 closed 3 years ago

Ozay34 commented 3 years ago

Note: Still a bit new to mongoose, when I refer to "entries", that is referring to items in an array, when I refer to "attributes" I am referring to the key/value pairs you set up in the mongoose schema.

If you create a new schema that has an attribute that is an array of either subdocuments or nested schemas, and those children have attributes that are set to be auto populated, only the first added entry will be populated upon calling save(). The rest will not (even after a fresh find). An example of a schema as such is shown below.

const ParentSchema = new mongoose.Schema({
    entries: [
        {
            name: String,
            model: {
                type: mongoose.Schema.Types.ObjectID,
                ref: PopulatedModel.modelName,
                autopopulate: true
            }
        }
    ]
});

Upon adding an entry to this array and saving for the first time, the model attribute will automatically be populated as expected, but if a second one is added and then saved, the second entry's model attribute will not be automatically populated.

I have traced this to index.js line 70. Mongoose returns a list of object Id's from this.populated, but if an entry is not populated, it will return undefined. The issue in this case is that even though the array entry is undefined, it still counts towards the total length.

If the entries themselves are the ones that need to be auto populated rather than being a subdocument or a nested schema's children, auto populate still works as expected.

Here is a zip file containing a sample project that outlines the issue: mongoose-autopopulate-bug.zip

To run the sample, extract it and CD into the new directory and npm install followed by npm start

Of course, please let me know if you need any further information.

vkarpov15 commented 3 years ago

What is the output you get from running your project? When I run it, I get the below output:

Document after save:  {
  _id: 5fa6b74fb10c06857f167d4f,
  entries: [
    { _id: 5fa6b74fb10c06857f167d50, name: 'Test', model: [Object] },
    {
      _id: 5fa6b74fb10c06857f167d51,
      name: 'Test 2',
      model: 5fa6b74fb10c06857f167d4e
    }
  ],
  __v: 1
}
Document after find:  [
  {
    _id: 5fa6b74fb10c06857f167d50,
    name: 'Test',
    model: { _id: 5fa6b74fb10c06857f167d4e, name: 'Populated', __v: 0 }
  },
  {
    _id: 5fa6b74fb10c06857f167d51,
    name: 'Test 2',
    model: { _id: 5fa6b74fb10c06857f167d4e, name: 'Populated', __v: 0 }
  }
]

The 2nd find() call looks like it works fine with autopopulate. Is the issue you're experiencing that the 2nd subdoc in "Document after save" isn't populated?

Ozay34 commented 3 years ago

The output I get is the same as what you posted.

The issue isn't with the second one after find, that's there to demonstrate that it is able to be auto-populated. The issue is with the first one after save. From my understanding, running save() should auto populate as long as there is something new to auto populate. You can see that the second entry has a model id associated with it, but it was not auto populated.

The document after find is how I would expect the document after save to look like, with the second entries model auto populated.

vkarpov15 commented 3 years ago

Fixed in mongoose-autopopulate@v0.12.3