【问题标题】:Mongoose aggregate to get Average rating, count each rate and return the actual ratingsMongoose 聚合得到平均评分,计算每个评分并返回实际评分
【发布时间】:2020-02-28 06:03:55
【问题描述】:

我试图获得产品的平均评分,加上每个评分的计数,并返回实际评分,并使用分页来限制返回的数量,而不影响平均或计数。

所以我正在尝试实现这样的目标:

这是我的评分集:

       {
            "productId": "3"
            "userid" : 5,
            "rating" : 5
            "comment": "this is nice"
        },
        {
            "productId": "3"
            "userid" : 2,
            "rating" :4
            "comment": "this is very nice"
        }

这就是我想要的结果

{
    "_id" : 1,
    "avgRating": "3.6"
    "counts" : [
        {
            "rating" : 5,
            "count" : 8
        },
        {
            "rating" : 3,
            "count" : 2
        },
        {
            "rating" : 4,
            "count" : 4
        },
        {
            "rating" : 1,
            "count" : 4
        }
    ],
   "ratings": [
       {
            "productId": "3"
            "userid" : 5,
            "rating" : 5
            "comment": "this is nice"
        },
        {
            "productId": "3"
            "userid" : 2,
            "rating" :4
            "comment": "this is very nice"
        },
        {
            "productId": "3"
            "userid" : 12,
            "rating" : 4
            "comment": "this is okay"
        }
    ]
}

到目前为止,我有这个给我每个评分的计数:

db.votes.aggregate([
    { $match: { postId: {$in: [1,2]} } },
    {
      $group: { _id: { post: "$postId", rating: "$vote" }, count: { $sum: 1 } }
    },
    {
      $group: {
        _id: "$_id.post",
        counts: { $push: { rating: "$_id.rating", count: "$count" } }
      }
    }
  ])

【问题讨论】:

  • 原始数据是什么样的?它是如何存储在 Mongo 中的。如果不知道你的 Mongo“模式”是什么样的,几乎不可能提供帮助。
  • 更新添加架构@MattOestreich

标签: node.js mongodb mongoose


【解决方案1】:

你已经不远了,我们只需要调整一些东西:

db.votes.aggregate([
    {
        $match:
            {
                postId: {$in: [1, 2]}
            }
    },
    {
        $group: {
            _id: {post: "$postId", rating: "$vote"},
            count: {$sum: 1},
            reviews: {$push : "$$ROOT" } //keep the original document
        }
    },
    {
        $group: {
            _id: "$_id.post",
            counts: {$push: {rating: "$_id.rating", count: "$count"}},
            reviews: {$push: "$reviews"},
            totalItemCount: {$sum: "$count"}, //for avg calculation
            totalRating: {$sum: "$_id.rating"} // //for avg calculation
        }
    },
    {
        $project: {
            _id: "$_id",
            avgRating: {$divide: ["$totalRating", "$totalItemCount"]},
            counts: "$counts",
            reviews: {
                $slice: [
                    {
                        $reduce: {
                            input: "$reviews",
                            initialValue: [],
                            in: { $concatArrays: ["$$value", "$$this"] }
                        }
                    },
                    0, //skip
                    10 //limit
                ]
            }

        }
    }
])

请注意,为了清楚起见,我保留了当前的管道结构,但是我觉得使用利用 $facet 的管道可能更有效,因为我们不必在分组时将整个集合保存在内存中。 我们将它分成两部分,一个是当前管道减去审查部分,一个只有$skip$limit 阶段。

编辑: $facet 版本:

db.votes.aggregate([
    {
        "$match": {
            "postId": {"$in": [1, 2]}
        }
    },
    {
        "$facet": {
            "numbers": [
                {
                    "$group": {
                        "_id": {
                            "post": "$postId",
                            "rating": "$vote"
                        },
                        "count": {
                            "$sum": 1.0
                        }
                    }
                },
                {
                    "$group": {
                        "_id": "$_id.post",
                        "counts": {
                            "$push": {
                                "rating": "$_id.rating",
                                "count": "$count"
                            }
                        },
                        "totalItemCount": {
                            "$sum": "$count"
                        },
                        "totalRating": {
                            "$sum": "$_id.rating"
                        }
                    }
                }
            ],
            "reviews": [
                {
                    "$skip": 0.0
                },
                {
                    "$limit": 10.0
                }
            ]
        }
    },
    {
        "$unwind": "$numbers"
    },
    {
        "$project": {
            "_id": "$numbers._id",
            "reviews": "$reviews",
            "avgRating": {"$divide": ["$numbers.totalRating", "$numbers.totalItemCount"]},
            "counts": "$numbers.counts"
        }
    }
]);

【讨论】:

  • 像魅力一样工作。你会建议什么指数? @tom-slabbaert
  • 只要确保 postId 被索引,没有其他索引与此管道相关。
  • 也可以发布 $facet 方法。因为我重视性能@tom-slabbaert
猜你喜欢
  • 2018-01-04
  • 1970-01-01
  • 2018-07-24
  • 2013-07-31
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
  • 2013-03-31
相关资源
最近更新 更多