4

There are many SO questions about mongoose's populate feature, but I've been unable to find evidence of whether this is possible, and if so, what I am doing wrong.

Let's say I'm making a blog. Yay. All users can write articles and post comments on other articles. I chose to model things this way:

Users:

var UserSchema = new Schema({
    name: String,
    email: {
        type: String,
        unique: true
    }
});
mongoose.model('User', UserSchema);

Articles with embedded comments:

var ArticleSchema = new Schema({
    title: {
        type: String
    },
    createdBy: {
        type: Schema.ObjectId,
        ref: 'User'
    },
    comments: [
        commentsSchema
    ]
)};

var commentSchema = new Schema({
    message: {
        type: String
    },
    createdBy: {
        type: Schema.ObjectId,
        ref: 'User'
    }
});

mongoose.model('Article', ArticleSchema);

When I want to load an article, I can use mongooseJS populate to load an article with its creator like so:

Article
.findOne({_id: articleid})
.populate('createdBy', 'name email')
.exec(function(err,article) {
    console.log('Created by %s', article.createdBy.name); // This works, yay.
});

But if I want to also load the comments with THEIR creators using populate, comment.createdBy is null:

Article
.findOne({_id: articleid})
.populate('createdBy', 'name email')
.populate('comments.createdBy', 'name email') //am I doing this correctly?
.exec(function(err,article) {
    console.log('First comment by %s', article.comments[0].createdBy.name); // Error, createdBy is null.
});

With that last version, I can see that article.comments[0].createdBy is null. I have verified that in the db the comment has a mongoose object ID for createdBy (and that it matches an existing user).

Is this possible?
- If so, where am I going wrong?
- If not, what is a better way to go about this? MongoDB questions like this one lead me to believe I'm on the right track, but perhaps mis-using mongoose?

Community
  • 1
  • 1

1 Answers1

1

It seems to be impossible to populate a double nested object like this, there might still be a way to do it but I haven't come across it. Another way to do it however could be to simply do it like this:

Article.findById(articleId, function(err, article) {
    if (err) {
        ...
    } else {
        Comment
            .find({_id: {$in: article.comments}})
            .populate('createdBy', 'name email')
            .exec(function(err, comments) {
                if (err) {
                    ...
                } else {
                    console.log('First comment by %s', comments[0].createdBy.name)
                }
            })
    }
})
Mattias Farnemyhr
  • 4,148
  • 3
  • 28
  • 49