javorosas
javorosas

Reputation: 769

Nested query with mongoose

I have three models: User, Post and Comment

var User = new Schema({
    name: String,
    email: String,
    password: String // obviously encrypted
});

var Post = new Schema({
    title: String,
    author: { type: Schema.ObjectId, ref: 'User' }
});

var Comment = new Schema({
    text: String,
    post: { type: Schema.ObjectId, ref: 'Post' },
    author: { type: Schema.ObjectId, ref: 'User' }
});

I need to get all posts in which the user has commented.

I know it should be a very simple and common use case, but right now I can't figure a way to make the query without multiple calls and manually iterating the results.

I've been thinking of adding a comments field to the Post schema (which I'd prefer to avoid) and make something like:

Post.find()
    .populate({ path: 'comments', match: { author: user } })
    .exec(function (err, posts) {
        console.log(posts);
    });

Any clues without modifying my original schemas?

Thanks

Upvotes: 1

Views: 3266

Answers (1)

chridam
chridam

Reputation: 103475

You have basically a couple of approaches to solving this.

1) Without populating. This uses promises with multiple calls. First query the Comment model for the particular user, then in the callback returned use the post ids in the comments to get the posts. You can use the promises like this:

var promise = Comment.find({ "author": userId }).select("post").exec();
promise.then(function (comments) {
    var postIds = comments.map(function (c) {
        return c.post;
    });
    return Post.find({ "_id": { "$in": postIds }).exec();
}).then(function (posts) {
    // do something with the posts here
    console.log(posts);

}).then(null, function (err) {
    // handle error here
});

2) Using populate. Query the Comment model for a particular user using the given userId, select just the post field you want and populate it:

var query = Comment.find({ "author": userId });
query.select("post").populate("post");
query.exec(function(err, results){    
    console.log(results);
    var posts = results.map(function (r) { return r.post; });
    console.log(posts);
}); 

Upvotes: 1

Related Questions