如何在MongoDB聚合中将空值放在单独的字段中,将其他字段放到不同的字段中?

时间:2015-07-06 08:53:41

标签: javascript mongodb mongodb-query aggregation-framework

我的收藏中有以下文件。

{
"_id" : ObjectId("55961a28bffebcb8058b4570"),
"title" : "BackOffice 2",
"cts" : NumberLong(1435900456),
"todo_items" : [
    {
        "id" : "55961a42bffebcb7058b4570",
        "task_desc" : "test 1",
        "completed_by" : "557fccb5bffebcf7048b457c",
        "completed_date" : NumberLong(1436161096)
    },
    {
        "id" : "559639afbffebcc7098b45a6",
        "task_desc" : "test 2",
        "completed_by" : "557fccb5bffebcf7048b457c",
        "completed_date" : NumberLong(1435911809)
    },
    {
        "id" : "559a22f5bffebcb0048b476c",
        "task_desc" : "test 3",
    }
],
"uts" : NumberLong(1436164853)
}

我需要一个聚合查询来执行以下操作,如果有字段" completed_by"和" completed_date"如果有一个非空值,则按下"已完成"数组字段,否则将它们推入"不完整的"字段。

以下是我想要的样本结果。

{
  "_id" : ObjectId("55961a28bffebcb8058b4570"),
  "completed" : [
     {
       "id":"557fccb5bffebcf7048b457c",
       "title":"test 1",
       "completed_by" : "557fccb5bffebcf7048b457c",
       "completed_date" : NumberLong(1436161096)
     },
     {
       "id":"557fccb5bffebcf7048b457c",
       "title":"test 1",
       "completed_by" : "557fccb5bffebcf7048b457c",
       "completed_date" : NumberLong(1436161096)
     }
    ],
 "incomplete":[
     {
       "id" : "559a22f5bffebcb0048b476c",
       "title" : "test 3"
     }
   ]
}

2 个答案:

答案 0 :(得分:2)

只要您的"数组"物品有"不同"标识符(他们有)有几种方法;

首先,实际上没有"汇总文件":

db.collection.aggregate([
    { "$project": {
        "title": 1,
        "cts": 1,
        "completed": { "$setDifference": [
            { "$map": {
                "input": "$todo_items",
                "as": "i",
                "in": {
                    "$cond": [
                        "$$i.completed_date",
                        "$$i",
                        false
                    ]
                }
            }},
           [false]
        ]},
        "incomplete": { "$setDifference": [
            { "$map": {
                "input": "$todo_items",
                "as": "i",
                "in": {
                    "$cond": [
                        "$$i.completed_date",
                        false,
                        "$$i"
                    ]
                }
            }},
           [false]
        ]}
    }}
])

这要求您至少在服务器上提供MongoDB 2.6才能使用所需的$map$setDifference运算符。考虑到所有工作都在一个$project阶段完成,它的速度非常快。

您应该只在"聚合跨文档"时使用的替代方案可用于支持MongoDB 2.2之后的聚合框架的所有版本:

db.collection.aggregate([
    { "$unwind": "$todo_items" },
    { "$group": {
        "_id": "$_id",
        "title": { "$first": "$title" },
        "cts": { "$first": "$cts" },
        "completed": { 
            "$addToSet": {
                "$cond": [
                    "$todo_items.completed_date",
                    "$todo_items",
                    null
                ]
            }
        },
        "incomplete": {
            "$addToSet": {
                "$cond": [
                    "$todo_items.completed_date",
                    null,
                    "$todo_items",
                ]
            }
        }
    }},
    { "$unwind": "$completed" },
    { "$match": { "completed": { "$ne": null } } },
    { "$group": {
        "_id": "$_id",
        "title": { "$first": "$title" },
        "cts": { "$first": "$cts" },
        "completed": { "$push": "$completed" },
        "incomplete": { "$first": "$incomplete" }
    }}
    { "$unwind": "$incomplete" },
    { "$match": { "incomplete": { "$ne": null } } },
    { "$group": {
        "_id": "$_id",
        "title": { "$first": "$title" },
        "cts": { "$first": "$cts" },
        "completed": { "$first": "$completed" },
        "incomplete": { "$push": "$incomplete" }
    }}
])

由于您需要满足数组可能最终为空的条件,因此并非全部存在。但这不是真正的教训,因为MongoDB 2.6已经流传了几年。

在聚合中,你不能真正排除" null / false"结果,但你可以"过滤"它们。

此外,除非您实际上是"汇总各个文件"如前所述,那么用$unwind处理数组的第二个表单带有一个" lot"开销。因此,您应该在读取每个文档时更改客户端代码中的数组内容。

答案 1 :(得分:0)

请查看以下内容:

{{1}}