Take the 2-minute tour ×

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.save(function(err, item){
                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_at    : { type: Date }
  , updated_at    : { type: Date }

var ItemSchema = new Schema({
  , comments  : [CommentSchema]
share|improve this question
Could you elaborate the schema –  almypal Oct 23 '12 at 9:14
What have you tried so far? Also as mentioned, the schema would be useful. –  jsalonen Oct 23 '12 at 12:48
i've pasted what I've tried, res.json() –  chovy Oct 23 '12 at 20:10

2 Answers 2

up vote 21 down vote accepted

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.createde_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,

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) {

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) {
            status: 'success',
            message: "You have commented on this item",
            comment: item.comments.id(comment._id)
share|improve this answer
I re-read your item.save() function, this mostly works, except I get all comments in the collection back, I just want the one I added. –  chovy Oct 24 '12 at 6:34
Ok, I had a small bug, populate('comments.created_by username') didn't work, but .populate('comments.created_by', 'username') did. Also I noticed I can use -salt -password_hash to not return those fields. Thanks a bunch! accepted answer. –  chovy Oct 24 '12 at 6:39
Oh wow! I didn't know you can use - prefix. Thanks for teaching me as well! :) –  jsalonen Oct 24 '12 at 9:08
@chovy can you please update the code with how you did the -salt -passowrd_hash. I searched the mongoose doc, but there was no reference to -salt. –  rajkamal Aug 2 '13 at 5:41
How to find a user's all written comments? –  Gank Jun 12 at 11:54

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.

share|improve this answer
This answer is much more correct that the one by @jsalonen. This way you don't have to fetch the document all over again. –  Chris Foster Dec 28 '13 at 23:54

Your Answer


