【问题标题】:Mongo shell query for survey stats($unwind with 2D array)Mongo shell 查询统计数据($unwind 与 2D 数组)
【发布时间】:2018-04-12 21:48:03
【问题描述】:

我的文档结构(仅提供 2 个):

 /* 1 */
{
    "_id" : ObjectId("59edc58af33e9b5988b875fa"),
    "Agent" : {
        "Name" : "NomanAgent",
        "Location" : "Lahore",
        "AgentId" : 66,
        "Suggestion" : [ 
            "Knowledge", 
            "Professionalisn"
        ]
    },
    "Rating" : 2,
    "Status" : "Submitted"
}
/* 2 */
 {
    "_id" : ObjectId("59edc58af33e9b5988b875fb"),
    "Agent" : {
        "Name" : "NomanAgent",
        "Location" : "Lahore",
        "AgentId" : 66,
        "Suggestion" : [ 
            "Knowledge", 
            "Clarity"
        ]
    },
    "Rating" : 1,
    "Status" : "Submitted"
}
/* 3 */
{
    "_id" : ObjectId("59edc58af33e9b5988b875fc"),
    "Agent" : {
        "Name" : "NomanAgent",
        "Location" : "Lahore",
        "AgentId" : 66,
        "Reward" : "Thumb Up"
    },
    "Rating" : 5,
    "Status" : "Submitted"
}

这些基本上是调查回复,因此代理对象可能包含建议(如果客户评论不佳)或奖励(如果客户满意),所以这里我显示 2 个带有建议的文档和 1 个带有奖励。

我已经为下面给出的奖励创建了一个查询,

db.getCollection('_survey.response').aggregate([
    {
        $group:{
            _id: "$Agent.Name",
            Rating: {$avg: "$Rating"},
            Rewards: {$push: "$Agent.Reward"},
            Status: {$push : "$Status"}
        }
    },
    {
        $unwind: "$Rewards"  
    },
    {
        $group:{
            _id: {
                Agent: "$_id",
                Rating: "$Rating",
                Rewards: "$Rewards"
            },
            RewardCount:{$sum: 1},
            SurveyStatus: {$first: "$Status"}

        }
    },
    {
        $group:{
            _id: "$_id.Agent",
            Rewards: {$push:{Reward: "$_id.Rewards", Count: "$RewardCount"}},
            Rating: {$first: "$_id.Rating"},
            SurveyStatus: {$first: "$SurveyStatus"}
        }
    },
    {
        $unwind: "$SurveyStatus"
    },
    {
        $group:{
            _id: {
                Agent: "$_id",
                Survey: "$SurveyStatus"
            },
            StatusCount:{$sum : 1},
            Rating: {$first: "$Rating"},
            Rewards: {$first: "$Rewards"}
        }
    },
    {
        $group:{
            _id: "$_id.Agent",
            Status:{$push:{Status: "$_id.Survey", Count: "$StatusCount"}},
            Rewards: {$first: "$Rewards"},
            Rating: {$first: "$Rating"}
        }
    },
    {
        $project:{
            _id: 0,
            Agent: "$_id",
            Rating: {
                $multiply:[
                    {$divide:["$Rating",5]},
                    100
                ]
            },
            Status: 1,
            Rewards: 1
        }
    }
]);

以上查询对于奖励非常有效,我想要完全相同的建议作为建议,如果可以在同一查询中调整建议,我会很高兴(我们也可以为建议创建单独的查询)。

上述给定查询的响应:

/* 1 */
{
    "Status" : [ 
        {
            "Status" : "Submitted",
            "Count" : 2.0
        }, 
        {
            "Status" : "Pending",
            "Count" : 1.0
        }, 
        {
            "Status" : "Opened",
            "Count" : 2.0
        }
    ],
    "Rewards" : [ 
        {
            "Reward" : "Thumb Up",
            "Count" : 1.0
        }, 
        {
            "Reward" : "Thank You",
            "Count" : 2.0
        }
    ],
    "Agent" : "GhazanferAgent",
    "Rating" : 68.0
}

/* 2 */
{
    "Status" : [ 
        {
            "Status" : "Opened",
            "Count" : 2.0
        }, 
        {
            "Status" : "Viewed",
            "Count" : 2.0
        }, 
        {
            "Status" : "Pending",
            "Count" : 3.0
        }
    ],
    "Rewards" : [ 
        {
            "Reward" : "Gift",
            "Count" : 1.0
        }, 
        {
            "Reward" : "Thumb Up",
            "Count" : 3.0
        }, 
        {
            "Reward" : "Thank You",
            "Count" : 1.0
        }
    ],
    "Agent" : "NomanAgent",
    "Rating" : 60.0
}

到目前为止,我已经尝试过,我想到了两种方法,但发现每种方法都有问题,

First(在数组中查找平均评分并推送状态和建议):

db.getCollection("_survey.response").aggregate([
    {
        $match:
        {
            $and:[
                {
                    "Agent.Suggestion":{
                        $exists: true
                    }
                },    
                {
                    Rating: {$lte: 3}
                }
            ]

        }
    },
    {
        $group:{
            _id: {
                AgentName: "$Agent.Name",
                AgentId: "$Agent.AgentId",
                Location: "$Agent.Location"
            },
            Rating: {$avg: "$Rating"},
            Status: {$push : "$Status"},
            Suggestions: {$push: "$Agent.Suggestion"}
        }
    }
]);

这种方法面临的问题是,投影中的建议将变成一个动态大小的数组数组(因为它最初是一个数组),具体取决于代理在客户响应中获得建议的次数。所以问题是在动态大小的二维数组上应用 $unwind

Second($unwind 将第一阶段的建议作为一维数组 避免在动态大小的二维数组上出现 $unwind 问题)

db.getCollection("_survey.response").aggregate([
    {
        $match:
        {
            $and:[
                {
                    "Agent.Suggestion":{
                        $exists: true
                    }
                },    
                {
                    Rating: {$lte: 3}
                }
            ]

        }
    },
    {
        $unwind: "$Agent.Suggestion"
    },
    {
        $group: {
            _id:{
                AgentName: "$Agent.Name",
                AgentId: "$Agent.AgentId",
                Suggestion: "$Agent.Suggestion",
                Location: "$Agent.Location"
            },
            Status: {$push: "$Status"},
            Rating: {$avg: "$Rating"},
            Count: {$sum: 1}
        }
    }
]);

使用这种方法的问题是 $unwind Suggestion array 它会将所有建议与他们各自的代理变平,从而增加文档的数量(与原始响应相比)所以我不会能够在此分组的基础上找到每个代理的平均评分的正确值,同样会发生状态(因为只有当我按代理分组时我才能正确找到这两个字段。虽然,这里我与代理一起分组建议),

我希望 Suggestion 查询得到完全相同的响应,只有响应中的 Rewards 对象会替换 Suggestions(或者如果我们可以在相同的响应中获得 Suggestions 对象,那就太好了)

调查状态可以是待定、已打开、已查看、已提交等

输出说明:

如您在上面提到的输出中所见,我想要每个代理的建议(带计数)、状态(带计数)和评分(我已经在做)。

提前致谢!!

【问题讨论】:

  • 您已经创建了相当复杂的奖励管道。是什么阻止您对 Suggestions 做同样的事情?
  • Rewards 只是一个键值对,而 Suggestions 是一个数组,这是我卡住的地方,当我展开以展平建议的数据。
  • 我可能是错的,我只是想将此查询转换为一些建议。
  • Rewards 是第一阶段之后的数组。可能值得将您的尝试添加到问题中与评级“混淆”的地方。目前还不太清楚您面临什么问题。

标签: mongodb mongodb-query aggregation-framework aggregation


【解决方案1】:

连续两次使用 $unwind 对我有用,使用第一种方法,

db.getCollection("_survey.response").aggregate([
    {
        $match:
        {
            $and:[
                {
                    "Agent.Suggestion":{
                        $exists: true
                    }
                },    
                {
                    Rating: {$lte: 3}
                }
            ]

        }
    },
    {
        $group:{
            _id: {
                AgentName: "$Agent.Name",
                AgentId: "$Agent.AgentId",
                Location: "$Agent.Location"
            },
            Rating: {$avg: "$Rating"},
            Status: {$push : "$Status"},
            Suggestions: {$push: "$Agent.Suggestion"}
        }
    },
    {
        $unwind: "$Suggestions"
    },
    {
        $unwind: "$Suggestions"
    },
    {
        $group: {
            _id: {
                Suggestions: "$Suggestions",
                AgentName: "$_id.AgentName",
                AgentId: "$_id.AgentId",
                Location: "$_id.Location"
            },
            SuggestionCount: {$sum: 1},
            Rating: {$first: "$Rating"},
            Status: {$first: "$Status"}
        }
    },
    {
        $group: {
           _id:{
                AgentName: "$_id.AgentName",
                AgentId: "$_id.AgentId",
                Location: "$_id.Location"
            },
            Suggestions: {$push:{Sugestion: "$_id.Suggestions", Count: "$SuggestionCount"}},
            TotalSuggestions: {$sum: "$SuggestionCount"},
            Rating: {$first: "$Rating"},
            Status: {$first: "$Status"}
        }

    },
    {
        $unwind: "$Status"
    },
    {
        $group:{
            _id: {
                AgentName: "$_id.AgentName",
                AgentId: "$_id.AgentId",
                Location: "$_id.Location",
                Status: "$Status"
            },
            StatusCount:{$sum : 1},
            Rating: {$first: "$Rating"},
            Suggestions: {$first: "$Suggestions"},
            TotalSuggestions: {$first: "$TotalSuggestions"}
        }
    },
    {
        $group:{
            _id: {
                AgentName: "$_id.AgentName",
                AgentId: "$_id.AgentId",
                Location: "$_id.Location"
            },
            Status:{$push:{Status: "$_id.Status", Count: "$StatusCount"}},
            TotalStatus: {$sum: "$StatusCount"},
            Suggestions: {$first: "$Suggestions"},
            TotalSuggestions: {$first: "$TotalSuggestions"},
            Rating: {$first: "$Rating"}
        }
    },
    {
        $project: {
            _id: 0,
            AgentName: "$_id.AgentName",
            AgentId: "$_id.AgentId",
            Location: "$_id.Location",
            Status: 1,
            TotalStatus: 1,
            Suggestions: 1,
            TotalSuggestions: 1,
            Performance: {
                $concat: [
                    {
                        $substr: [
                            {
                                $multiply:[
                                    {$divide:["$Rating",5]},
                                    100
                                ]

                            }, 0, 4
                        ]
                    },"%"
                ]
            }
        }
    }
]);

【讨论】:

    猜你喜欢
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多