I am using express + mongoose and in general the populate method works fine. There is one case however, where it is not working. Neither does it show any errors:
I have an assignments model, which has some modules:
import { Model, Schema, model } from 'mongoose';
import { IAssignment } from '../interfaces/app/IAssignment';
// Define Mongoose schema for Assignment
const AssignmentSchema = new Schema<IAssignment>(
{
name: { type: String, trim: true, required: true },
modules: [
{
module: { type: Schema.Types.ObjectId, ref: 'AssignmentModule' },
dueDate: { type: Date },
},
],
},
);
// Create and export Mongoose model
const Assignment: Model<IAssignment> = model<IAssignment>(
'Assignment',
AssignmentSchema
);
export default Assignment;
and there is another model for AssignmentModule
import { IAssignmentModule } from '../interfaces/app/IAssignmentModule';
const Schema = mongoose.Schema;
// Define Mongoose schema for Module
const AssignmentModuleSchema = new Schema<IAssignmentModule>(
{
title: { type: String },
questions: [{ type: Schema.Types.ObjectId, ref: 'Question' }],
},
{ timestamps: true, versionKey: false }
);
// Create and export Mongoose model
const AssignmentModule: Model<IAssignmentModule> =
mongoose.model<IAssignmentModule>('AssignmentModule', AssignmentModuleSchema);
export default AssignmentModule;
And this is my controller function, which should give me all assignments with modules.module
populated.
const assignments: IAssignment[] = await Assignment.find().populate([
{ path: 'modules', populate: 'modules.module' },
]);
My eventual goal is to populate modules.module, and then inside the module, there is a questions reference as well, which needs to be populated with some selected fields, lets say name
and score
. I understand I can chain the populate, but my first population itself is not happening. Is there any issue naming your field as module? Or there is something else that is missing here?
The modules
are subdocuments, see Alternate declaration syntax for arrays. The populate path should be modules.module
.
E.g.
import mongoose from 'mongoose';
import util from 'util';
import { config } from '../../config';
mongoose.set('debug', true);
console.log(mongoose.version);
const QuestionSchema = new mongoose.Schema({
score: Number,
});
const Question = mongoose.model('Question', QuestionSchema);
const AssignmentModuleSchema = new mongoose.Schema({
title: { type: String },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }],
});
const AssignmentModule = mongoose.model('AssignmentModule', AssignmentModuleSchema);
const AssignmentSchema = new mongoose.Schema({
modules: [
{
module: { type: mongoose.Schema.Types.ObjectId, ref: 'AssignmentModule' },
dueDate: { type: Date },
},
],
});
const Assignment = mongoose.model('Assignment', AssignmentSchema);
(async function main() {
try {
await mongoose.connect(config.MONGODB_URI);
await Promise.all([Question, Assignment, AssignmentModule].map((m) => m.collection.drop()));
// seed
const [q1] = await Question.create([{ score: 100 }, { score: 80 }]);
const [m1] = await AssignmentModule.create([{ title: 'a', questions: [q1] }, { title: 'b' }]);
await Assignment.create([{ modules: [{ module: m1, dueDate: Date.now() }] }, { modules: [] }]);
// test
const assignmentDocs = await Assignment.find().populate({
path: 'modules.module',
select: '-__v',
populate: { path: 'questions', select: '-__v' },
});
console.log(util.inspect(assignmentDocs, false, null));
} catch (error) {
console.error(error);
} finally {
await mongoose.connection.close();
}
})();
Debug logs:
[
{
_id: new ObjectId("64a807003389777bbfe22f2f"),
modules: [],
__v: 0
},
{
_id: new ObjectId("64a807003389777bbfe22f2d"),
modules: [
{
module: {
_id: new ObjectId("64a807003389777bbfe22f29"),
title: 'a',
questions: [
{
_id: new ObjectId("64a807003389777bbfe22f25"),
score: 100
}
]
},
dueDate: 2023-07-07T12:37:20.672Z,
_id: new ObjectId("64a807003389777bbfe22f2e")
}
],
__v: 0
}
]