Empty array prevents document to appear in query

∥☆過路亽.° 提交于 2020-01-03 18:49:42

问题


I have documents that have a few fields and in particular the have a field called attrs that is an array. I am using the aggregation pipeline.

In my query I am interested in the attrs (attributes) field if there are any elements in it. Otherwise I still want to get the result. In this case I am after the field type of the document.

The problem is that if a document does not contain any element in the attrs field it will be filtered away and I won't get its _id.type field, which is what I really want from this query.

{
    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
            }
        }
    ]
}

So the question is: how can I get a result containing all documents types regardless of their having attrs, but including the attributes in case they have them?

I hope it makes sense.


回答1:


You can use the $cond operator in a $project stage to replace the empty attr array with one that contains a placeholder like null that can be used as a marker to indicate that this doc doesn't contain any attr elements.

So you'd insert an additional $project stage like this right before the $unwind:

    {
        $project: {
            attrs: {$cond: {
               if: {$eq: ['$attrs', [] ]},
               then: [null],
               else: '$attrs'
           }}
        }
    },

The only caveat is that you'll end up with a null value in the final attrs array for those groups that contain at least one doc without any attrs elements, so you need to ignore those client-side.

Example

The example uses an altered $match stage because the one in your example isn't valid.

Input Docs

[
  {_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}]}
]

Output

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

Aggregate Command

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
        }
    }
])



回答2:


use some if statements and loops.

first, your query should select all documents, first and foremost.

loop through all of them

then, if number of attributes is greater than 0, loop through the attributes. loop them into whatever array or output you find useful.

use if statements to sanitize your results if you like.




回答3:


You should use '$or' operator , and two seperate queries : one to select the documents with attr value equal to required value, and other query to match documents where attr is null, or attr key does not exist ( using $exists operator )



来源:https://stackoverflow.com/questions/27510143/empty-array-prevents-document-to-appear-in-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!