【问题标题】:Mongoose — Create new property with $sum using aggregationMongoose — 使用聚合创建具有 $sum 的新属性
【发布时间】:2016-04-04 06:16:59
【问题描述】:

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

这是 Schema(为简洁起见,删除了不相关的字段):

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

我建立模型:

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

我使用聚合来创建一个包含投票数组总和的新字段。

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

当我启动我的服务器时,我没有收到任何错误;但是,totalVotes 字段尚未创建。我使用this 文档来帮助我。它同样使用$sum 运算符,我完全按照文档说明的方式进行操作,但没有结果。

【问题讨论】:

  • @Vishnu 我已经定义了架构?
  • 无法获取模型中未定义的字段。这就是问题所在。
  • @Vishnu 聚合框架的结果不受模型模式的限制,可以是任何东西。所以这不是问题,而是你不能在$project 内应用$sum,也不能直接在数组上应用。

标签: javascript node.js mongodb mongodb-query aggregation-framework


【解决方案1】:

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

【讨论】:

  • 我认为这不起作用,因为我使用的是 Mongoose
【解决方案2】:

不幸的是,这并没有像您想象的那样起作用,因为“投票”实际上是一个值数组,其次是因为$sumaccumulator operator,仅用于$group 管道阶段。

所以为了让你得到数组的总和作为另一个属性,首先你必须$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”字段始终可以使用,而无需解构数组并对每个文档的值求和。

【讨论】:

    【解决方案3】:

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

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

    resultData.toJSON();
    

    【讨论】:

    • 我试了一下,文档中显示了字段,但是值只是一个空数组
    • @Matthew 试试更新的代码。 totalVotes 应该是一个数字,而不是一个数组:P。
    【解决方案4】:

    @Blakes Seven 和 @Volodymyr Synytskyi 帮助我找到了解决方案!我还发现 this 文档特别有用。

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

    【讨论】:

      猜你喜欢
      • 2016-02-17
      • 1970-01-01
      • 2021-08-23
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-08
      相关资源
      最近更新 更多