mongoose – 用$ sum使用聚合创build新的属性

我试图在包含数字数组之和的所有文档中添加一个新字段。

这里是架构(为简洁起见删除无关字段):

var PollSchema = new Schema( { votes: [Number] } ); 

我build立模型:

 PollModel = mongoose.model('Poll', PollSchema); 

我使用聚合创build一个新的字段,其中包含投票数组的总和。

 PollModel.aggregate([ { $project: { totalVotes: { $sum: "$votes"} } } ]); 

当我启动我的服务器,我没有得到任何错误; 但是, totalVotes字段尚未创build。 我用这个文档来帮助我。 它同样使用$sum运算符,我完全像文档说明的那样,但没有结果。

不幸的是,这并不像你想象的那样工作,因为“票数”实际上是一组数值,其次是因为$sum只是在$grouppipe道阶段中使用的累加器操作符 。

所以为了让你获得数组的总数作为另一个属性,首先你必须$unwind数组,然后在文档关键字上$group$sum的元素:

 PostModel.aggregate( [ { "$unwind": "$votes" }, { "$group": { "_id": "$_id", "anotherField": { "$first": "$anotherField" }, "totalVotes": { "$sum": "$votes" } }} ], function(err,results) { } ); 

另外还要注意,在$first另一个累加器对于每个你想要的结果字段都是必需的,因为$group$project只返回你要求的字段。

一般来说,由于性能方面的原因,最好在每个文档中保留属性,因为它比使用聚合更快。 所以要做到这一点只是增加一个总和,每次你$push到一个数组同时也使用$inc

 PostModel.update( { "_id": id }, { "$push": { "votes": 5 }, "$inc": { "totalVotes": 5 } }, function(err,numAffected) { } ); 

通过这种方式,“totalVotes”字段总是可以使用,而不需要解构数组和总结每个文档的值的开销。

MongoDb聚合不会将其结果保存到数据库中。 您只需在callback中获得内联聚合的结果。 所以聚合之后,你需要对你的数据库进行多重更新:

 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) { }); }) }); 

您的架构中没有totalVotes 。 试试下面的代码。

 var PollSchema = new Schema( { votes: [Number], totalVotes: Number } ); PollModel.aggregate([ { $project: { totalVotes: { $sum: "$votes"} } } ]); 

要么

 resultData.toJSON(); 

@Blakes七和@Volodymyr Synytskyi帮助我到达我的解决scheme! 我也发现这个文件特别有用。

 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); } } }); } );