Skip to content

Commit f8c705e

Browse files
committed
fix: mark documents that are populated using hydratedPopulatedDocs option as populated in top-level doc
Fix Automattic#15048
1 parent cf50772 commit f8c705e

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

lib/document.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,14 @@ function init(self, obj, doc, opts, prefix) {
805805
reason: e
806806
}));
807807
}
808+
} else if (opts.hydratedPopulatedDocs) {
809+
doc[i] = schemaType.cast(value, self, true);
810+
811+
if (doc[i] && doc[i].$__ && doc[i].$__.wasPopulated) {
812+
self.$populated(path, doc[i].$__.wasPopulated.value, doc[i].$__.wasPopulated.options);
813+
} else if (Array.isArray(doc[i]) && doc[i].length && doc[i][0]?.$__?.wasPopulated) {
814+
self.$populated(path, doc[i].map(populatedDoc => populatedDoc?.$__?.wasPopulated?.value).filter(val => val != null), doc[i][0].$__.wasPopulated.options);
815+
}
808816
} else {
809817
doc[i] = value;
810818
}

lib/schemaType.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,8 +1567,9 @@ SchemaType.prototype._castRef = function _castRef(value, doc, init) {
15671567
!doc.$__.populated[path].options ||
15681568
!doc.$__.populated[path].options.options ||
15691569
!doc.$__.populated[path].options.options.lean) {
1570-
ret = new pop.options[populateModelSymbol](value);
1571-
ret.$__.wasPopulated = { value: ret._doc._id };
1570+
const PopulatedModel = pop ? pop.options[populateModelSymbol] : doc.constructor.db.model(this.options.ref);
1571+
ret = new PopulatedModel(value);
1572+
ret.$__.wasPopulated = { value: ret._doc._id, options: { [populateModelSymbol]: PopulatedModel } };
15721573
}
15731574

15741575
return ret;

test/model.hydrate.test.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,10 @@ describe('model', function() {
108108
users: [{ ref: 'User', type: Schema.Types.ObjectId }]
109109
});
110110

111-
db.model('UserTestHydrate', userSchema);
112-
const Company = db.model('CompanyTestHyrdrate', companySchema);
111+
db.deleteModel(/User/);
112+
db.deleteModel(/Company/);
113+
db.model('User', userSchema);
114+
const Company = db.model('Company', companySchema);
113115

114116
const users = [{ _id: new mongoose.Types.ObjectId(), name: 'Val' }];
115117
const company = { _id: new mongoose.Types.ObjectId(), name: 'Booster', users: [users[0]] };
@@ -144,6 +146,7 @@ describe('model', function() {
144146
count: true
145147
});
146148

149+
db.deleteModel(/User/);
147150
const User = db.model('User', UserSchema);
148151
const Story = db.model('Story', StorySchema);
149152

@@ -173,5 +176,26 @@ describe('model', function() {
173176

174177
assert.strictEqual(hydrated.storiesCount, 2);
175178
});
179+
180+
it('sets hydrated docs as populated (gh-15048)', async function() {
181+
const userSchema = new Schema({
182+
name: String
183+
});
184+
const companySchema = new Schema({
185+
name: String,
186+
users: [{ ref: 'User', type: Schema.Types.ObjectId }]
187+
});
188+
189+
db.deleteModel(/User/);
190+
const User = db.model('User', userSchema);
191+
const Company = db.model('Company', companySchema);
192+
193+
const users = [{ _id: new mongoose.Types.ObjectId(), name: 'Val' }];
194+
const company = { _id: new mongoose.Types.ObjectId(), name: 'Acme', users: [users[0]] };
195+
196+
const c = Company.hydrate(company, null, { hydratedPopulatedDocs: true });
197+
assert.ok(c.populated('users'));
198+
assert.ok(c.users[0] instanceof User);
199+
});
176200
});
177201
});

0 commit comments

Comments
 (0)