使用sort计算每个文档的平均值

时间:2017-05-29 21:30:01

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

我有一个如此定义的猫鼬模型:

freelancerSchema = mongoose.Schema({
 _id: { type: String, default: shortid.generate},
 fname: String,
 lname: String;
 ratings: [{
       rating: Number,
       employer: {
          type: String,
          ref: 'Employer'
           }
        }],
 ...
}]

此架构表示Freelancer集合的猫鼬模型。我的问题是:在某个查询中,我需要找到所有自由职业者的所有数据,并计算每个人的平均评分。最后,我会得到一系列自由职业者,每个人都有自己的计算平均评分,最好存储在一个新的字段“avg_rating”或类似的东西中。

我已经尝试过调查mongodb Aggregate,但老实说我并不太了解。

如果我的解释不够准确,请提前致谢并对不起。

2 个答案:

答案 0 :(得分:2)

如果我们要在这里播放code golf,那么可以缩短表达式:

Freelancer.aggregate([
  { "$addFields": {
    "rating_avg": {
       "$reduce": {
        "input": "$ratings",
        "initialValue": 0,
        "in": {
          "$add": [ 
            "$$value",
            { "$divide": [ "$$this.rating", { "$size": "$ratings" } ] }
          ]
        }
      }
    }
  }},
  { "$sort": { "rating_avg": -1 } }
],function(err, results) {
  res.send(results)
})

甚至使用$avg$map缩短了一点:

Freelancer.aggregate([
  { "$addFields": {
    "rating_avg": {
      "$avg": {
        "$map": { 
          "input": "$ratings",
          "as": "el",
          "in": "$$el.rating"
        }
      }
    }
  }},
  { "$sort": { "rating_avg": -1 } }
],function(err, results) {
  res.send(results)
})

当然是最短的,自MongoDB 3.2以来被允许(当然用$project修改):

Freelancer.aggregate([
  { "$addFields": {
    "rating_avg": { "$avg": "$ratings.rating" }
  }},
  { "$sort": { "rating_avg": -1 } }
],function(err, results) {
  res.send(results)
})

当使用$addFields可用的MongoDB 3.4时,所有人都使用$project作为$reduce的替代。使用$project修改时的第二种形式也对MongoDB 3.2有效,第三种形式也是如此(并注明)。

答案 1 :(得分:1)

在搞乱我的代码并阅读其他一些堆栈之后,我发现了一个适合我需求的解决方案:

   Freelancer.aggregate(
    [{
            $project: {
                fname: "$fname",
                lname: "$lname",
                rating_avg: {
                    $divide: [{
                        $reduce: {
                            input: "$ratings.rating",
                            initialValue: 0,
                            in: {
                                $sum: ["$$value", "$$this"]
                            }
                        }
                    }, {
                        $size: "$ratings"
                    }]
                }
            }
        },
        {
            $sort: {
                rating_avg: -1
            }
        }
    ],
    function (err, results) {
        res.send(results);
    });
});

希望将来可以帮助其他人。