如何在查询父项时获取聚合的mongoose子文档数组中的值的总和?

我正在尝试在express和mongoose之上构build一些先进的Hello World应用程序。 假设我有下一个Schema:

const pollOptionsSchema = new Schema({ name: String, votes: { type: Number, default: 0 } }); const pollSchema = new Schema({ name: String, dateCreated: { type: Date, default: Date.now }, author: { type: Schema.Types.ObjectId }, options: [pollOptionsSchema] }); 

而当我只是打电话

 Poll.findOne({_id: req.params.id}).exec((err, data) => { if (err) console.log(err); // I receive next data: // { _id: 58ef3d2c526ced15688bd1ea, // name: 'Question', // author: 58dcdadfaea29624982e2fc6, // __v: 0, // options: // [ { name: 'stack', _id: 58ef3d2c526ced15688bd1ec, votes: 5 }, // { name: 'overflow', _id: 58ef3d2c526ced15688bd1eb, votes: 3 } ], // dateCreated: 2017-04-13T08:56:12.044Z } }); 

问题是如何在模型级别上调用某种方法后可以得到相同的数据+总计票数(即上面的情况下为8),例如:

  // I want to receive: // { _id: 58ef3d2c526ced15688bd1ea, // name: 'Question', // author: 58dcdadfaea29624982e2fc6, // __v: 0, // totalNumberOfVotes: 8, // options: // [ { name: 'stack', _id: 58ef3d2c526ced15688bd1ec, votes: 5 }, // { name: 'overflow', _id: 58ef3d2c526ced15688bd1eb, votes: 3 } ], // dateCreated: 2017-04-13T08:56:12.044Z } 

或者,也许我需要在文档级别上实现一些额外的方法,即(data.aggregate)?

我已经阅读:

  1. http://mongoosejs.com/docs/api.html#model_Model.mapReduce
  2. http://mongoosejs.com/docs/api.html#aggregate_Aggregate
  3. https://docs.mongodb.com/manual/core/map-reduce/
  4. https://docs.mongodb.com/manual/tutorial/map-reduce-examples/

但不能用于我的情况:(

任何意见将不胜感激。 谢谢!

$addFieldsstream水线中使用$reduce操作符来创build$addFields字段。 在您的聚合pipe道中,第一步是$match ,它过滤文档stream,只允许匹配的文档未经修改地传递到下一个pipe道阶段,并使用标准的MongoDB查询。

考虑运行下面的集合操作来获得所需的结果:

 Poll.aggregate([ { "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } }, { "$addFields": { "totalNumberOfVotes": { "$reduce": { "input": "$options", "initialValue": 0, "in": { "$add" : ["$$value", "$$this.votes"] } } } } } ]).exec((err, data) => { if (err) console.log(err); console.log(data); }); 

注意:以上将适用于MongoDB 3.4及更高版本。


对于其他较早的版本,您需要首先$unwind options数组,然后在$grouppipe道步骤中对非规范化文档进行分组,然后与累加器$sum$push$first汇总。

以下示例显示了这种方法:

 Poll.aggregate([ { "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } }, { "$unwind": { "path": "$options", "preserveNullAndEmptyArrays": true } }, { "$group": { "_id": "$_id", "totalNumberOfVotes": { "$sum": "$options.votes" }, "options": { "$push": "$options" }, "name": { "$first": "$name" }, "dateCreated": { "$first": "$dateCreated" }, "author": { "$first": "$author" } } } ]).exec((err, data) => { if (err) console.log(err); console.log(data); });