简体   繁体   English

在 $project 聚合阶段获取一个子文档字段

[英]get a sub document field in $project stage of aggregation

I'm working with the followings schemas:我正在使用以下模式:

Question Schema:问题架构:

var Question = new Schema({
      title: String,
      content: String,
      createdBy: {
          type: Schema.ObjectId,
          ref: 'User',
          required: true
        },
      answers: {
         type: [ { type: Schema.Types.ObjectId, ref: 'Answer' } ]
       }
    });

Answer Schema:答案架构:

var Answer = new Schema({
     content:String,
     createdBy: {
         type: Schema.Types.ObjectId,
         ref: 'User',
      },
     isBest: {
         type: Boolean,
         default: false
   },
    createdAt: Date,
    votes: Number    
});

I'm trying to do an aggregation where I can have as result the list of all questions with a certain fields like title , createdBy (which is going to be populated after the aggregate) , an answers_count and a has_best field which is going to be true if a question already have a best answer (an answer with the field isBest equals to true) .我正在尝试进行聚合,结果我可以得到所有问题的列表,其中包含特定字段,如titlecreatedBy (将在聚合后填充)answers_counthas_best字段,这将是如果question已经有最佳答案(字段 isBest 的答案等于 true),则为 true

I've try with the $project pipeline:我尝试使用$project管道:

  Question.aggregate([{
  $project: {
    answers_count: { $size: '$answers' },
    title: true,
    createdAt: true,
    createdBy: true,
    has_best_answer: '$answers.isBest'
  }
}, {
  $sort: {
    createdAt: -1
  }
}], function(err, questions){
  if(err){
    return res.status(400).send({ message: err });
  }
  User.populate(questions, { path: 'createdBy', model: 'User', select: 'firstname lastname image' }, function(err, questions){
    return res.json(questions);
  });
});

Also I've try to $unwind the array and then $lookup for answers but no results when doing an answers_count .此外,我尝试$unwind数组,然后$lookup寻找答案,但在执行answers_count时没有结果。 This is what I've tried with $unwind and $lookup .这是我用$unwind$lookup尝试过的。

Question.aggregate([
  {
    $unwind: '$answers'
  },
  {
    $lookup: {
      from: 'answers',
      localField: 'answers',
      foreignField: '_id',
      as: 'answer'
    }
  },{
    $project: {
      title: true,
      createdBy: true,
      createdAt: true,
      has_best_answer: '$answer.isBest'
    }
  }
], function(err, questions){
  if(err){
    return res.status(400).send({ message: err });
  }
  User.populate(questions, { path: 'createdBy', model: 'User', select:
      'firstname lastname image' }, function(err, questions){
    return res.json(questions);
  });
});

So, because the $unwind in the array, cannot $size in answers array to do an answers_count field, also when I tried to do $group to having uniques questions id like this:因此,因为数组中的$unwind不能在 answers 数组中使用$size来执行answers_count字段,所以当我尝试使用$group来获得唯一questions id时,如下所示:

Question.aggregate([
  {
    $unwind: '$answers'
  },
  {
    $lookup: {
      from: 'answers',
      localField: 'answers',
      foreignField: '_id',
      as: 'answer'
    }
  },{
    $project: {
      title: true,
      createdBy: true,
      createdAt: true,
      has_best_answer: '$answer.isBest'
    }
  },
  {
    $group: { _id: '$_id' }
  }
], function(err, questions){
  if(err){
    return res.status(400).send({ message: err });
  }
  User.populate(questions, { path: 'createdBy', model: 'User', select: 'firstname lastname image' }, function(err, questions){
    return res.json(questions);
  });
});

I have this result:我有这个结果:

[
   {
      "_id": "5825f2846c7ab9ec004f14ce"
   },
   {
      "_id": "5823b9309de40494239c95cd"
   },
   {
      "_id": "582538366062607c0f4bcdaa"
   },
   {
      "_id": "5855d319b6a475100c7beba2"
   },
   {
    "_id": "5878156328dba3d02052b321"
   }
 ]

This is the output that I'm looking for:这是我正在寻找的输出:

[
   {
      _id: '5825f2846c7ab9ec004f14ce',
      title: 'Some question title',
      createdBy: '5855d319b6a475100c7beba2', // this is going to be       populated,
      createdAt: '2016-11-10T00:02:56.702Z',
      answers_count: 5,
      has_best_answer: true
   },
  {
     _id: '5825f2846c7ab9ec004f14ce',
     title: 'Some other question title',
     createdBy: '5855d319b6a475100c7beba2', // this is going to be populated,
     createdAt: '2016-11-10T00:02:56.702Z',
     answers_count: 2,
     has_best_answer: false
  }
]

You can try something like below.你可以试试下面的方法。

$lookup - This stage joins all the answers to a question documents. $lookup - 此阶段将问题文档的所有answers结合起来。

$project - This stage projects all the required fields. $project - 此阶段投影所有必填字段。 answers_count - Counts the total the number of items in an answers array. answers_count - 计算answers数组中的项目总数。 has_best_answer - Iterates an answers and compares if any of the isBest field value is true. has_best_answer - 迭代answers并比较任何isBest字段值是否为真。

Question.aggregate([
  {
    $lookup: {
      from: 'answers',
      localField: 'answers',
      foreignField: '_id',
      as: 'answers'
    }
  },{
    $project: {
      title: true,
      createdBy: true,
      createdAt: true,
      answers_count: { $size: '$answers' },
      has_best_answer: 
        { $anyElementTrue: {
            $map: {
                input: "$answers",
                as: "answer",
                in: { $eq: [ "$$answer.isBest", true] }
            }
        }}
    }
  }
]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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