2

我有一个评级模型,其中包含一本书和评级值。我想获取数据库中每本书的所有评级计数(评级从 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,
            }
            .
            .
            .
            .
        ]
    }

我该怎么做?

4

1 回答 1

3

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

{
    "$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)

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

db.ratings.aggregate([
    { 
        "$match": {
            "book": {
                "$in": [
                    ObjectId("57e111142a52fe257e5d1d42"), 
                    ObjectId('57e6bef7cad79fa38555c643')
                ]
            }
        }
    },
    { 
        "$group": {
            "_id": { 
                "book": "$name",
                "rating": "$rating"
            },
            "count": { "$sum": 1 }
        }
    },
    { 
        "$group": {
            "_id": "$_id.book",
            "counts": {
                "$push": {
                    "rating": "$_id.rating",
                    "count": "$count"
                }
            }
        }
    }
])
于 2016-09-25T13:25:32.520 回答