我有一组用户,每个文档都有以下结构:
{
"_id": "<id>",
"login": "xxx",
"solved": [
{
"problem": "<problemID>",
"points": 10
},
...
]
}
字段solved
可能为空或包含任意多个子文档。我的目标是获得一个用户列表以及总分(points
之和),其中尚未解决任何问题的用户将被分配总分为0.这是否可以通过一个单独执行此操作查询(理想情况下使用聚合框架)?
我试图在聚合框架中使用以下查询:
{ "$group": {
"_id": "$_id",
"login": { "$first": "$login" },
"solved": { "$addToSet": { "points": 0 } }
} }
{ "$unwind": "$solved" }
{ "$group": {
"_id": "$_id",
"login": { "$first": "$login" },
"solved": { "$sum": "$solved.points" }
} }
但是我收到了以下错误:
exception: The top-level _id field is the only field currently supported for exclusion
提前谢谢
答案 0 :(得分:56)
使用MongoDB 3.2及更新版本时, $unwind
运算符现在有一些选项,特别是preserveNullAndEmptyArrays
选项可以解决此问题。
如果此选项设置为true,并且路径为空,缺失或空数组, $unwind
将输出文档。如果为false,则 $unwind
如果路径为空,缺失或为空数组,则不会输出文档。在您的情况下,将其设置为true:
db.collection.aggregate([
{ "$unwind": {
"path": "$solved",
"preserveNullAndEmptyArrays": true
} },
{ "$group": {
"_id": "$_id",
"login": { "$first": "$login" },
"solved": { "$sum": "$solved.points" }
} }
])
答案 1 :(得分:7)
这是解决方案 - 它假定“已解决”字段要么缺席,要么等于null或者有一系列问题并且分数已经解决。它没有处理的情况是“解决”是一个空数组 - 虽然这可以是一个简单的额外调整,你可以添加。
project = {$project : {
"s" : {
"$ifNull" : [
"$solved",
[
{
"points" : 0
}
]
]
},
"login" : 1
}
};
unwind={$unwind:"$s"};
group= { "$group" : {
"_id" : "$_id",
"login" : {
"$first" : "$login"
},
"score" : {
"$sum" : "$s.points"
}
}
}
db.students.aggregate( [ project, unwind, group ] );