将书籍分组并计算每个评级

时间:2016-09-25 13:12:08

标签: mongodb mongoose mongodb-query aggregation-framework mongodb-aggregation

我有一个评级模型,其中包含书籍和评级值。我想获得数据库中每本书的所有评级数(评级从1到5不等)。

我的架构看起来像 -

    {
      "_id": ObjectId("57e112312a52fe257e5d1d5c"),
      "book": ObjectId("57e111142a52fe257e5d1d42"),
      "rating": 4
    }
    {
      "_id": ObjectId("57e7a002420d22d6106a4715"),
      "book": ObjectId("57e111142a52fe257e5d1d42"),
      "rating": 5
    }
    {
      "_id": ObjectId("57e7a4cd98bfdb5a11962d54"),
      "book": ObjectId("57e111142a52fe257e5d17676"),
      "rating": 5
    }
    {
      "_id": ObjectId("57e7a4cd98bfdb5a11962d54"),
      "book": ObjectId("57e111142a52fe257e5d17676"),
      "rating": 1
    }

目前,我只能达到这一点,我可以获得每本书的评级,但它没有明确指定评级值。

这是我当前的查询 -

    db.ratings.aggregate([
        {$match: {book: {$in: [ObjectId("57e111142a52fe257e5d1d42"), ObjectId('57e6bef7cad79fa38555c643')]}}},
        {$group: {_id: {book: "$book", value: "$value"} } },
        {$group: {_id: "$_id.book", total: {$sum: 1}}},
    ])

输出是这个 -

    {
        "result": [
            {
                "_id": ObjectId("57e6bef7cad79fa38555c643"),
                "total": 2
            },
            {
                "_id": ObjectId("57e111142a52fe257e5d1d42"),
                "total": 2
            }
        ],
        "ok": 1
    }

但是,我想联合所有文件并获得rating字段的每个值的评分计数结果,如下所示。重点是我只想要每本书的每个值的评级计数。

    {
        result: [
            {
                _id: "57e111142a52fe257e5d17676",
                5_star_ratings: 1,
                4_star_ratings: 3,
                3_star_ratings: 4,
                2_star_ratings: 1,
                1_star_ratings: 0,
            },
            {
                _id: "57e111142a52fe257e5d1d42",
                5_star_ratings: 10,
                4_star_ratings: 13,
                3_star_ratings: 7,
                2_star_ratings: 8,
                1_star_ratings: 19,
            }
            .
            .
            .
            .
        ]
    }

我该怎么做?

1 个答案:

答案 0 :(得分:2)

完成任务需要 $cond 管道,该管道使用 $sum $cond 运算符>累加器操作员。 $sum 运算符将根据其第一个参数(if)计算逻辑条件,然后返回第二个参数,其中评估为true(然后)或第三个参数,其中false(else) 。这会将true / false逻辑转换为分别输入 {{3}} 的1和0数值:

$group

作为结果操作,您可能希望运行以下聚合管道:

{
    "$sum": { 
        "$cond": [ { "$eq": [ "$rating", 1 ] }, 1, 0 ]
    }
}

对于比上述方法执行速度更快的更灵活,性能更好的方法,请考虑运行替代管道,如下所示

var pipeline = [
    { 
        "$match": {
            "book": {
                "$in": [
                    ObjectId("57e111142a52fe257e5d1d42"), 
                    ObjectId('57e6bef7cad79fa38555c643')
                ]
            }
        }
    },
    { 
        "$group": { 
            "_id": "$book",             
            "5_star_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", 5 ] }, 1, 0 ]
                }
            },
            "4_star_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", 4 ] }, 1, 0 ]
                }
            },
            "3_star_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", 3 ] }, 1, 0 ]
                }
            },
            "2_star_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", 2 ] }, 1, 0 ]
                }
            },
            "1_star_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", 1 ] }, 1, 0 ]
                }
            }           
        }  
    },
]

db.ratings.aggregate(pipeline)