MongoDB aggregation with unwind on empty array

时间:2015-06-25 18:45:35

标签: mongodb aggregation-framework

I have a collection of documents in MongoDB, where each document has a subdocument containing an array. { _id: <id> key1: "value1", key2: "value2", ... versions: [ { version: 2, key1: <othervalue2>, key2: <othervalue2>} { version: 1, key1: <othervalue2>, key2: <othervalue2>} ] } I want to query the collection and return the document with ALL its fields, along with the elements of the array that match certain parameters (or an empty array when none match). With my current code, I'm only able to get a result when there's AT LEAST one element of the array that matches. I'm using these parameters for aggregation: {$match: {_id: <someID>}}, {$unwind: '$versions'}, {$match: {'versions.version': {$gte: <version>}}}, {$group: {_id: '$_id', key1: {$first: '$key1'}, ..., 'versions': {$push: '$versions'}} For example, querying where arrayelement.version >= 2 should return (this works with the current code): { _id: <id> key1: "value1", key2: "value2", ... versions: [ { version: 2, key1: <othervalue2>, key2: <othervalue2>} ] } And querying where arrayelement.version >= 4 should return: { _id: <id> key1: "value1", key2: "value2", ... versions: [] } None of the solutions I have seen address the issue of returning an object even when the array is empty. Is this even possible?

3 个答案:

答案 0 :(得分:4)

您可以检查版本数组是否为空,如果是,则添加一些占位符,例如空文档。省略管道的其余部分可能是这样的:

[
    {
        "$project" : {
            "versions" : {
                "$cond" : {
                    "if" : {"$eq" : [{"$size" : "$versions" }, 0]},
                    "then" : [{ }],
                    "else" : "$versions"
                }
            },
            "_id" : 1
        }
    },
    {
        "$unwind" : "$versions"
    }
]

请注意,管道中的{$match: {'versions.version'}}会将其过滤掉,因此您必须调整此部分。

答案 1 :(得分:0)

感谢zero323让我走上正轨。完整过滤器位于

之下
{$match: {_id: <someid>}},
{
    "$project" : {
        "versions" : {
            "$cond" : {
                "if" : {$or: [{$eq : [{$size : "$versions" }, 0]},{$eq : ["$version", <version>]}]},
                "then" : [null],
                "else" : "$versions"
            }
        },
        "_id" : 1,
        "key1": 1,
        "key2": 1,
        ...
        "version": 1

    }
},
{$unwind: '$versions'},
{$match: {$or: [{'versions.version':{ $exists: false}},{'versions.version': {$gte: <version>}}]}},
{$group: {_id:'$_id',key1:{$first: '$key1'}, key2:{$first: '$key2'},...,version:{$first:'$version'},versions:{$push: '$versions'}}},
{
    "$project" : {
        "versions" : {
            "$cond" : {
                "if" : {$eq : ["$versions", [null]]},
                "then" : [],
                "else" : "$versions"
            }
        },
        "_id" : 1,
        "key1": 1,
        "key2": 1,
        ...
        "version": 1
    }
}

答案 2 :(得分:0)

从MongoDb 3.2开始,$unwind运营商支持preserveNullAndEmptyArrays:<boolean>

因此,当preserveNullAndEmptyArrays:true时,它还将包含没有任何数据或空数据的值。

代码更改-

{$unwind: {path: '$versions', preserveNullAndEmptyArrays: true} },

有关更多信息,请访问-https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#document-operand-with-options