$ unwind empty array

Kar*_*rak 22 mongodb aggregation-framework

我有一组用户,每个文档都有以下结构:

{
  "_id": "<id>",
  "login": "xxx",
  "solved": [
    {
      "problem": "<problemID>",
      "points": 10
    },
    ...
  ]
}
Run Code Online (Sandbox Code Playgroud)

该字段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" }
} }
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

exception: The top-level _id field is the only field currently supported for exclusion
Run Code Online (Sandbox Code Playgroud)

先感谢您

chr*_*dam 65

使用MongoDB 3.2及更新版本,$unwind运营商现在有一些选项,特别是该preserveNullAndEmptyArrays选项将解决这个问题.

如果此选项设置为true,并且路径为null,缺少或空数组,则$unwind输出文档.如果为false,$unwind则在路径为空,缺失或空数组时不输出文档.在您的情况下,将其设置为true:

db.collection.aggregate([
    { "$unwind": {
            "path": "$solved",
            "preserveNullAndEmptyArrays": true
    } },
    { "$group": {
        "_id": "$_id",
        "login": { "$first": "$login" },
        "solved": { "$sum": "$solved.points" }
    } }
])
Run Code Online (Sandbox Code Playgroud)

  • 很好的问题和很好的答案。你拯救了我的一天 (2认同)

Asy*_*sky 8

这是解决方案 - 它假设"已解决"字段要么不存在,要么等于null或者有一系列问题并且分数已经解决.它没有处理的情况是"解决"是一个空数组 - 虽然这可以是一个简单的额外调整,你可以添加.

project = {$project : {
        "s" : {
            "$ifNull" : [
                "$solved",
                [
                    {
                        "points" : 0
                    }
                ]
            ]
        },
        "login" : 1
    }
};
unwind={$unwind:"$s"};
group= { "$group" : {
        "_id" : "$_id",
        "login" : {
            "$first" : "$login"
        },
        "score" : {
            "$sum" : "$s.points"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

db.students.aggregate( [ project, unwind, group ] );