猫鼬 — 使用聚合创建具有$sum的新属性
Mongoose — Create new property with $sum using aggregation
我正在尝试在所有包含数字数组总和的文档中添加一个新字段。
以下是架构(为简洁起见,删除了不相关的字段(:
var PollSchema = new Schema(
{
votes: [Number]
}
);
我建立模型:
PollModel = mongoose.model('Poll', PollSchema);
我使用聚合创建一个包含 votes 数组总和的新字段。
PollModel.aggregate([
{
$project: {
totalVotes: { $sum: "$votes"}
}
}
]);
启动服务器时,没有收到任何错误;但是,尚未创建totalVotes
字段。 我使用这个文档来帮助我。 它同样使用 $sum
运算符,我完全按照文档说明的那样做了,但没有结果。
MongoDb 聚合不会将其结果保存到数据库中。您只需在回调中获取内联聚合的结果。因此,在聚合后,您需要对数据库进行多次更新:
PollModel.aggregate([
{
$project: { totalVotes: { $sum: "$votes"} }
}]).exec( function(err, docs){
// bulk is used for updating all records within a single query
var bulk = PollModel.collection.initializeUnorderedBulkOp();
// add all update operations to bulk
docs.forEach(function(doc){
bulk.find({_id: doc._id}).update({$set: {totalVotes: doc.totalVotes}});
});
// execute all bulk operations
bulk.execute(function(err) {
});
})
});
不幸的是,
这并不像您想象的那样工作,因为"votes"实际上是一个值数组,其次是因为$sum
是一个累加器运算符,仅用于$group
管道阶段。
因此,为了获得数组的总数作为另一个属性,首先您必须$unwind
数组,然后在文档键上一起$group
以$sum
元素的总数:
PostModel.aggregate(
[
{ "$unwind": "$votes" },
{ "$group": {
"_id": "$_id",
"anotherField": { "$first": "$anotherField" },
"totalVotes": { "$sum": "$votes" }
}}
],
function(err,results) {
}
);
这里还要注意的是,对于您希望在结果中作为$group
的每个附加字段,$first
中的另一个累加器都是必需的,$project
只返回您要求的字段。
通常,出于性能原因,最好将其保留为每个文档中的属性,因为它比使用聚合更快。因此,要做到这一点,只需在每次$push
数组时增加一个总数,同时使用 $inc
:
PostModel.update(
{ "_id": id },
{
"$push": { "votes": 5 },
"$inc": { "totalVotes": 5 }
},
function(err,numAffected) {
}
);
通过这种方式,"totalVotes"字段始终可以使用,而无需解构数组并对每个文档的值求和。
您的架构中没有totalVotes
。只需尝试以下代码。
var PollSchema = new Schema(
{
votes: [Number],
totalVotes: Number
}
);
PollModel.aggregate([
{
$project: {
totalVotes: { $sum: "$votes"}
}
}
]);
或
resultData.toJSON();
@Blakes Seven 和 @Volodymyr Synytskyi 帮助我找到了解决方案! 我还发现这个文档特别有用。
PollModel.aggregate(
[
{ '$unwind': '$votes' },
{ '$group': {
'_id': '$_id',
'totalVotes': { '$sum': '$votes' }
}}
],
function(err,results) {
// console.log(results);
results.forEach(function(result){
var conditions = { _id: result._id },
update = { totalVotes: result.totalVotes },
options = { multi: true };
PollModel.update(conditions, update, options, callback);
function callback (err, numAffected) {
if(err) {
console.error(err);
return;
} else {
// console.log(numAffected);
}
}
});
}
);
相关文章:
- 创建新属性后的 JSON 空属性
- chart.js 2.0为数据集添加了新属性
- 当组件准备就绪时,如何在Polymer中动态注册新属性
- 为for循环中的对象添加新属性
- 复制第一个属性's值,然后使用第一个属性的值创建新属性
- 调用ko.applyBindings后,向Knockout视图模型添加新属性
- 如何向JSON数组添加新属性
- 在对象上迭代并添加新属性
- 在AngularJS中对指令的隔离作用域设置新属性
- 在knocket js中应用绑定后,向视图模型添加新属性
- 护照个人资料未通过新属性
- 如何在 CKEditor 表的单元格属性中添加新属性
- 无法向 Mongoose 查询返回的对象添加新属性
- 有没有办法让 Javascript 在将新属性添加到给定对象时抛出错误
- W3C 设置新属性
- 是否可以向现有 JSON 数据添加新属性
- 使用 contructor 参数将新属性添加到原型
- 如何为 html5 标签创建新属性
- 创建新属性 - JS / 边缘动画
- 猫鼬 — 使用聚合创建具有$sum的新属性