简体   繁体   中英

MongoDB Query from multiple models / schemas and return in one field

I am using Nodejs and MongoDB , mongoose and expressjs, creating a Blog API having users, articles, likes & comments schema. Below are schemas that I use.


    const UsersSchema = new mongoose.Schema({
      username:        { type: String },
      email:           { type: String },
      date_created:    { type: Date },
      last_modified:   { type: Date }
    });


    const ArticleSchema = new mongoose.Schema({
      id:              { type: String, required: true },
      text:            { type: String, required: true }, 
      posted_by:       { type: Schema.Types.ObjectId, ref: 'User', required: true },
      images:          [{ type: String }],
      date_created:    { type: Date },
      last_modified:   { type: Date }
    });


    const CommentSchema = new mongoose.Schema({
      id:             { type: String, required: true },
      commented_by:   { type: Schema.Types.ObjectId, ref: 'User', required: true },
      article:        { type: Schema.Types.ObjectId, ref: 'Article' },
      text:           { type: String, required: true },
      date_created:   { type: Date },
      last_modified:  { type: Date } 
    });

What I actually need is when I * get collection of articles * I also want to get the number of comments together for each articles. How do I query mongo?

Since you need to query more than one collection, you can use MongoDB's aggregation.

Here: https://docs.mongodb.com/manual/aggregation/

Example:

Article
  .aggregate(
    {
      $lookup: {
        from: '<your comments collection name',
        localField: '_id',
        foreignField: 'article',
        as: 'comments'
      }
    },
    {
      $project: {
        comments: '$comments.commented_by',
        text: 1,
        posted_by: 1,
        images: 1,
        date_created: 1,
        last_modified: 1
      }
    },
    {
      $project: {
        hasCommented: {
          $cond: {
            if: { $in: [ '$comments', '<user object id>' ] },
            then: true,
            else: false
          }
        },
        commentsCount: { $size: '$comments' },
        text: 1,
        posted_by: 1,
        images: 1,
        date_created: 1,
        last_modified: 1
      }
    }
  )

The aggregation got a little big but let me try to explain: First we need to filter the comments after the $lookup . So we $unwind them, making each article contain just one comment object, so we can filter using $match (that's the filter stage, it works just as the <Model>.find() . After filtering the desired's user comments, we $group everything again, $sum: 1 for each comment, using as the grouper _id, the article's _id. And we get the $first result for $text, $images and etc. Later, we $project everything, but now we add hasCommented with a $cond , simply doing: if the $comments is greater than 0(the user has commented, so this will be true , else, false .

MongoDB's Aggregation framework it's awesome and you can do almost whatever you want with your data using it. But be aware that somethings may cost more than others, always read the reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM