空数组可防止文档出现在查询中

时间:2014-12-16 17:12:04

标签: mongodb aggregation-framework

我的文档中包含一些字段,特别是有一个名为 attrs 的字段是一个数组。我正在使用聚合管道。

在我的查询中,如果其中有任何元素,我对 attrs (属性)字段感兴趣。否则我仍然想得到结果。在这种情况下,我在文档的字段 type 之后。

问题是如果文档中不包含 attrs 字段中的任何元素,它将被过滤掉,我将不会获得其 _id.type 字段,这是我真正想要的查询。

{
    aggregate: "entities",
    pipeline: [
        {
            $match: {
                _id.servicePath: {
                    $in: [
                        /^/.*/,
                        null
                    ]
                }
            }
        },
        {
            $project: {
                _id: 1,
                "attrs.name": 1,
                "attrs.type": 1
            }
        },
        {
            $unwind: "$attrs"
        },
        {
            $group: {
                _id: "$_id.type",
                attrs: {
                    $addToSet: "$attrs"
                }
            }
        },
        {
            $sort: {
                _id: 1
            }
        }
    ]
}

所以问题是:如何获得包含所有文档类型的结果,无论他们是否具有 attrs ,但是如果他们拥有这些文档,还包括属性?

我希望这是有道理的。

3 个答案:

答案 0 :(得分:4)

您可以在$project阶段使用$cond运算符将空attr数组替换为包含可用作标记的null占位符的数组attr数组表示此文档不包含任何$project元素。

因此,您需要在$unwind之前插入一个额外的 { $project: { attrs: {$cond: { if: {$eq: ['$attrs', [] ]}, then: [null], else: '$attrs' }} } }, 阶段:

null

唯一需要注意的是,对于那些包含至少一个没有任何attrs元素的文档的组,您最终会在最终attrs数组中获得$match值,所以你需要忽略那些客户端。

示例

该示例使用了更改的[ {_id: {type: 1, id: 2}, attrs: []}, {_id: {type: 2, id: 1}, attrs: []}, {_id: {type: 2, id: 2}, attrs: [{name: 'john', type: 22}, {name: 'bob', type: 44}]} ] 阶段,因为您示例中的某个阶段无效。

输入文档

{
    "result" : [ 
        {
            "_id" : 1,
            "attrs" : [ 
                null
            ]
        }, 
        {
            "_id" : 2,
            "attrs" : [ 
                {
                    "name" : "bob",
                    "type" : 44
                }, 
                {
                    "name" : "john",
                    "type" : 22
                }, 
                null
            ]
        }
    ],
    "ok" : 1
}

<强>输出

db.test.aggregate([
    {
        $match: {
            '_id.servicePath': {
                $in: [
                    null
                ]
            }
        }
    },
    {
        $project: {
            _id: 1,
            "attrs.name": 1,
            "attrs.type": 1
        }
    },
    {
        $project: {
            attrs: {$cond: {
               if: {$eq: ['$attrs', [] ]},
               then: [null],
               else: '$attrs'
           }}
        }
    },
    {
        $unwind: "$attrs"
    },
    {
        $group: {
            _id: "$_id.type",
            attrs: {
                $addToSet: "$attrs"
            }
        }
    },
    {
        $sort: {
            _id: 1
        }
    }
])

汇总命令

{{1}}

答案 1 :(得分:-1)

使用一些if语句和循环。

首先,您的查询应首先选择所有文档。

遍历所有这些

然后,如果属性数大于0,则遍历属性。将它们循环到您认为有用的任何数组或输出中。

如果您愿意,可以使用if语句来清理结果。

答案 2 :(得分:-1)

您应该使用'$或'运算符,以及两个单独的查询:一个用于选择attr值等于所需值的文档,另一个查询用于匹配attr为null或attr键不存在的文档(使用{ {1}}运营商)