Effect
Mongoose's populate() can join tables to query, referencing documents in other collections.
Populate() automatically replaces the specified field in the document, and the replacement content is obtained from other collection s.
refs
When you create a Model, you can set the ref option for fields in that Model that are associated to store other collection_id s.The ref option tells Mongoose which Model to use when populate() is populated.
const authorSchema = new Schema({ name: String, age: Number, story: { type: Schema.Types.ObjectId, ref: 'Story' } friends: [{ type: Schema.Types.ObjectId, ref: 'User' }] }); let Author = mongoose.model('Author', authorSchema);
In the example above, the friends field of Author model is set to an ObjectId array.The ref option tells Mongoose to use the User model when populating.All _ids stored in friends must be the _id of the document in the User Model.
ObjectId, Number, String, and Buffer can all be used as refs.But it's best to use ObjectId.
When you create a document, save the refs field as you would a regular property, just assign the value of _id to it.
let author = new Author({ name: 'dora', age: 18, story: story._id // Assigning story's_id directly }); await author.save();
populate(path, select)
Fill in the document
let author = await Author.findOne({ name: 'dora' }).populate('story'); author.story // {...} Documents found in the Story table
The filled story field is no longer the original_id but is replaced by the specified document.This document is returned from the database by another query.
The refs array returns an array of document s that store the corresponding_id.
No document associated
If there is no associated document, the return value is null, that is, author.story is null; if the field is an array, the return value is [] an empty array, that is, author.friends is [].
let author = await Author.findOne({ name: 'dora' }).populate('friends'); author.friends // []
Return Field Selection
If only a portion of the field in the document needs to be filled in, a second parameter can be passed to populate(), which returns a field string in the form of a parameter. Query.prototype.select().
let author = await Author.findOne({ name: 'dora' }).populate('story', 'title -_id'); author.story // Returns only the title field author.story.content // Null The rest of the fields are null
populate multiple fields
let author = await Author.findOne({ name: 'dora' }).populate('story').populate('friends');
If populate() is used twice for the same field, only the last time is valid.
populate({ objParam })
objParam:
- path: The field of populate is required.
- populate: Multilevel fill.
- select: select the returned field from the populate's document.
- Model: The associated model for populate.If not specified, populate will find the model based on the name in the ref field defined in the schema.You can specify a cross-database model.
- Conditions for match:populate queries.
-
Options:populate query options.
- Sort: sort.
- Limit: limit quantity.
Multilevel Filling
// Query friends for friends Author.findOne({ name: 'dora' }).populate({ path: 'friends', populate: { path: 'friends' } });
Filling across databases
Cross-database cannot be populated directly with the ref option in the schema, but a cross-database model can be explicitly specified with the model option in objParam.
let eventSchema = new Schema({ name: String, conversation: ObjectId // Note that ref is not specified here! }); let conversationSchema = new Schema({ numMessages: Number }); let db1 = mongoose.createConnection('localhost:27000/db1'); let db2 = mongoose.createConnection('localhost:27001/db2'); // Model s for different databases let Event = db1.model('Event', eventSchema); let Conversation = db2.model('Conversation', conversationSchema); // Show the specified model let doc = await Event.find().populate({ path: 'conversation', model: Conversation })
Model s populated by refPath dynamic reference
Mongoose can also query and populate multiple different collections for the same field that stores the_id.
//The schema used to store comments.Users can comment on blog posts or works. const commentSchema = new Schema({ body: { type: String, required: true }, on: { type: Schema.Types.ObjectId, required: true, refPath: 'onModel' }, onModel: { type: String, required: true, enum: ['BlogPost', 'Product'] } }); const Product = mongoose.model('Product', new Schema({ name: String })); const BlogPost = mongoose.model('BlogPost', new Schema({ title: String })); const Comment = mongoose.model('Comment', commentSchema);
The refPath option is more complex than Ref.If ref is just a string, Mongoose queries the same model to find the filled subdocument.With refPath, you can configure a model for each different document.
const book = await Product.create({ name: 'dissolve into undue laughter during a performance' }); const blog = await BlogPost.create({ title: 'Classic quotations in the laughing house, sharp sentences, direct heart' }); // Two comment data from different sources are specified const commentOnBook = await Comment.create({ body: 'Bravo', on: book._id, onModel: 'Product' }); const commentOnBlog = await Comment.create({ body: 'I laughed before I said anything.When the laughter is over, listen to me.', on: blog._id, onModel: 'BlogPost' });
const comments = await Comment.find().populate('on'); comments[0].on.name; // "Laughing ground" comments[1].on.title; // "Classic quotations from the laughing house..."
Of course, separate blogPost and product fields can also be defined in commentSchema to store _id and corresponding ref options, respectively.However, this is not conducive to business expansion, such as adding user reviews for songs or movies to subsequent businesses, and more related fields need to be added to the schema.A populate() query is required for each field.Using refPath means that no matter how many models commentSchema can point to, only one populate () is needed to federate queries.