I am adding a comment to an item.comments list. I need to get the comment.created_by user data before I output it in the response. How should I do this?
Item.findById(req.param('itemid'), function(err, item){ var comment = item.comments.create({ body: req.body.body , created_by: logged_in_user }); item.comments.push(comment); item.save(function(err, item){ res.json({ status: 'success', message: "You have commented on this item", //how do i populate comment.created_by here??? comment: item.comments.id(comment._id) }); }); //end item.save }); //end item.find
I need to populate the comment.created_by field here in my res.json output:
comment: item.comments.id(comment._id)
comment.created_by is a user reference in my mongoose CommentSchema. It currently is only giving me a user id, I need it populated with all the user data, except for password and salt fields.
Here is the schema as people have asked:
var CommentSchema = new Schema({ body : { type: String, required: true } , created_by : { type: Schema.ObjectId, ref: 'User', index: true } , created_at : { type: Date } , updated_at : { type: Date } }); var ItemSchema = new Schema({ name : { type: String, required: true, trim: true } , created_by : { type: Schema.ObjectId, ref: 'User', index: true } , comments : [CommentSchema] });
In Mongoose, subdocuments are documents that are nested in other documents. You can spot a subdocument when a schema is nested in another schema. Note: MongoDB calls subdocuments embedded documents.
Mongoose Populate() Method. In MongoDB, Population is the process of replacing the specified path in the document of one collection with the actual document from the other collection.
With the latest version of mongoose (mongoose >= 3.6), you can but it requires a second query, and using populate differently. After your aggregation, do this: Patients. populate(result, {path: "patient"}, callback);
In order to populate referenced subdocuments, you need to explicitly define the document collection to which the ID references to (like created_by: { type: Schema.Types.ObjectId, ref: 'User' }
).
Given this reference is defined and your schema is otherwise well defined as well, you can now just call populate
as usual (e.g. populate('comments.created_by')
)
Proof of concept code:
// Schema var mongoose = require('mongoose'); var Schema = mongoose.Schema; var UserSchema = new Schema({ name: String }); var CommentSchema = new Schema({ text: String, created_by: { type: Schema.Types.ObjectId, ref: 'User' } }); var ItemSchema = new Schema({ comments: [CommentSchema] }); // Connect to DB and instantiate models var db = mongoose.connect('enter your database here'); var User = db.model('User', UserSchema); var Comment = db.model('Comment', CommentSchema); var Item = db.model('Item', ItemSchema); // Find and populate Item.find({}).populate('comments.created_by').exec(function(err, items) { console.log(items[0].comments[0].created_by.name); });
Finally note that populate
works only for queries so you need to first pass your item into a query and then call it:
item.save(function(err, item) { Item.findOne(item).populate('comments.created_by').exec(function (err, item) { res.json({ status: 'success', message: "You have commented on this item", comment: item.comments.id(comment._id) }); }); });
This might have changed since the original answer was written, but it looks like you can now use the Models populate function to do this without having to execute an extra findOne. See: http://mongoosejs.com/docs/api.html#model_Model.populate. You'd want to use this inside the save handler just like the findOne is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With