猫鼬:聚合和计数

时间:2016-09-12 17:08:48

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

我有一个NodeJS / MongoDB应用程序,其数据存储在名为"Feedback"的集合中。数据如下所示:

[
    {
        "__v": 0,
        "_id": "57d6b2d09f46ca14440ac14e",
        "customerFeedback": [
            {
                "_id": "57d6b2d09f46ca14440ac14f",
                "answer": [
                    {
                        "_id": "57d6b2d09f46ca14440ac150",
                        "answerValue": "cat",
                        "answerWeight": 0
                    }
                ],
                "question": "What is your favourite thing about this shop?",
                "questionId": "57d65edc0132461120fa0afd"
            },
            {
                "_id": "57d6b2d09f46ca14440ac151",
                "answer": [
                    {
                        "_id": "57d6b2d09f46ca14440ac152",
                        "answerValue": "Okay",
                        "answerWeight": 0
                    }
                ],
                "question": "How was your experience today?",
                "questionId": "57d69ef6dbb25611e46e6bc9"
            }
        ],
        "shopId": "SH0001",
        "feedbackCreatedOn": "2016-09-12T13:51:12.703Z",
        "questionsForDay": "2016-09-12T00:00:00Z"
    },
    {
        "__v": 0,
        "_id": "57d6b3389f46ca14440ac157",
        "customerFeedback": [
            {
                "_id": "57d6b3389f46ca14440ac158",
                "answer": [
                    {
                        "_id": "57d6b3389f46ca14440ac159",
                        "answerValue": "cat",
                        "answerWeight": 0
                    }
                ],
                "question": "What is your favourite thing about this shop?",
                "questionId": "57d65edc0132461120fa0afd"
            },
            {
                "_id": "57d6b3389f46ca14440ac15a",
                "answer": [
                    {
                        "_id": "57d6b3389f46ca14440ac15b",
                        "answerValue": "Very Good",
                        "answerWeight": 0
                    }
                ],
                "question": "How was your experience today?",
                "questionId": "57d69ef6dbb25611e46e6bc9"
            },
            {
                "_id": "57d6b3389f46ca14440ac15c",
                "answer": [
                    {
                        "_id": "57d6b3389f46ca14440ac15d",
                        "answerValue": "Cost",
                        "answerWeight": 0
                    }
                ],
                "question": "What would you like us to improve on?",
                "questionId": "57d6b32d9f46ca14440ac153"
            }
        ],
        "shopId": "SH0001",
        "feedbackCreatedOn": "2016-09-12T13:52:56.939Z",
        "questionsForDay": "2016-09-12T00:00:00Z"
    },
    {
        "__v": 0,
        "_id": "57d6c8eb97157f10a4e5c2e7",
        "customerFeedback": [
            {
                "_id": "57d6c8eb97157f10a4e5c2e8",
                "answer": [
                    {
                        "_id": "57d6c8eb97157f10a4e5c2ea",
                        "answerValue": "Customer Experience",
                        "answerWeight": 0
                    },
                    {
                        "_id": "57d6c8eb97157f10a4e5c2e9",
                        "answerValue": "Others",
                        "answerWeight": 0
                    }
                ],
                "question": "What would you like us to improve on?",
                "questionId": "57d6b7d99ee61e47f01e5334"
            }
        ],
        "shopId": "SH0003",
        "feedbackCreatedOn": "2016-09-12T15:25:31.724Z",
        "questionsForDay": "2016-09-12T00:00:00Z"
    }
]

结果数组中有许多这样的条目,但上述数据用于说明它。

我的问题是,对于给定的shopIdquestionId,我想计算每个人answerValue出现的次数。我该怎么做?

我可以使用find方法(例如)

将结果过滤到所需的数据集
db.Feedback.find({shopId:"SH0001",'customerFeedback.questionId':"57d65edc0132461120fa0afd"})

但我不确定如何将数据聚合到我想要的格式。

1 个答案:

答案 0 :(得分:2)

此管道应该为您提供所需的结果

db.getCollection("yourCollection").aggregate([
    { $unwind: "$customerFeedback" },
    { $unwind: "$customerFeedback.answer" },
    { 
        $group: {
            _id: {
                shopId: "$shopId",
                questionId: "$customerFeedback.questionId",
                answerValue: "$customerFeedback.answer.answerValue"
            },
            count: { $sum: 1 }
        }
    }
])

为您的样本数据提供以下输出

/* 1 */
{
    "_id" : {
        "shopId" : "SH0003",
        "questionId" : "57d6b7d99ee61e47f01e5334",
        "answerValue" : "Others"
    },
    "count" : 1.0
}

/* 2 */
{
    "_id" : {
        "shopId" : "SH0003",
        "questionId" : "57d6b7d99ee61e47f01e5334",
        "answerValue" : "Customer Experience"
    },
    "count" : 1.0
}

/* 3 */
{
    "_id" : {
        "shopId" : "SH0001",
        "questionId" : "57d65edc0132461120fa0afd",
        "answerValue" : "cat"
    },
    "count" : 2.0
}

/* 4 */
{
    "_id" : {
        "shopId" : "SH0001",
        "questionId" : "57d69ef6dbb25611e46e6bc9",
        "answerValue" : "Okay"
    },
    "count" : 1.0
}

/* 5 */
{
    "_id" : {
        "shopId" : "SH0001",
        "questionId" : "57d6b32d9f46ca14440ac153",
        "answerValue" : "Cost"
    },
    "count" : 1.0
}

/* 6 */
{
    "_id" : {
        "shopId" : "SH0001",
        "questionId" : "57d69ef6dbb25611e46e6bc9",
        "answerValue" : "Very Good"
    },
    "count" : 1.0
}

当然,如果您只对特定值感兴趣,可以使用额外的$match阶段过滤结果

由于评论而更新:

要使用$match过滤结果,您可以在展开嵌套的客户反馈数据后使用它

...
{ $unwind: "$customerFeedback" },
{ $match: { shopId: "SH0001", "customerFeedback.questionId": "57d65edc0132461120fa0afd" } },
{ $unwind: "$customerFeedback.answer" },
{ 
    $group: {
        _id: {
            shopId: "$shopId",
            questionId: "$customerFeedback.questionId",
            answerValue: "$customerFeedback.answer.answerValue"
        },
        count: { $sum: 1 }
    }
}
...  

会导致

{
    "_id" : {
        "shopId" : "SH0001",
        "questionId" : "57d65edc0132461120fa0afd",
        "answerValue" : "cat"
    },
    "count" : 2.0
}

如果您在shopId和/或customerFeedback.questionId上有大量文档或索引,那么您可能希望将$match阶段复制到管道的前面,以便您仅展开相应商店的文档并至少对所需问题的一个反馈进行解除。因此(从正确的角度来看,可选的优化)看起来就像这样

...
{ $match: { shopId: "SH0001", "customerFeedback.questionId": "57d65edc0132461120fa0afd" } },
{ $unwind: "$customerFeedback" },
{ $match: { shopId: "SH0001", "customerFeedback.questionId": "57d65edc0132461120fa0afd" } },
{ $unwind: "$customerFeedback.answer" },
{ 
    $group: {
        _id: {
            shopId: "$shopId",
            questionId: "$customerFeedback.questionId",
            answerValue: "$customerFeedback.answer.answerValue"
        },
        count: { $sum: 1 }
    }
}
...