查询父项时如何获取猫鼬子文档数组中的值的聚合总和?
Posted
技术标签:
【中文标题】查询父项时如何获取猫鼬子文档数组中的值的聚合总和?【英文标题】:How to get aggregated sum of values in an array of mongoose subdocuments when query parent? 【发布时间】:2017-09-09 07:48:55 【问题描述】:我正在尝试在 express 和 mongoose 之上构建一些高级的 hello world 应用程序。假设我有下一个架构:
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)?
我已经评论过:
-
http://mongoosejs.com/docs/api.html#model_Model.mapReduce
http://mongoosejs.com/docs/api.html#aggregate_Aggregate
https://docs.mongodb.com/manual/core/map-reduce/
https://docs.mongodb.com/manual/tutorial/map-reduce-examples/
但不能用于我的情况:(
任何建议将不胜感激。谢谢!
【问题讨论】:
现在我只是遍历选项并在变量中收集总数。let sumVotes = 0; data.options.forEach((el) => sumVotes += el.votes );
【参考方案1】:
在 $addFields
管道中使用 $reduce
运算符来创建 totalNumberOfVotes
字段。在您的聚合管道中,第一步是 $match
过滤文档流以仅允许匹配的文档未经修改地传递到下一个管道阶段并使用标准 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
数组,然后在 $group
管道步骤中对非规范化文档进行分组并与累加器 $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);
);
【讨论】:
以上是关于查询父项时如何获取猫鼬子文档数组中的值的聚合总和?的主要内容,如果未能解决你的问题,请参考以下文章