如何将多个文档中的两个字段数组合并为一个集合?

4

我有一份MongoDB集合的数据,看起来像这样:

{ "_id" : "1", "array1" : [ "1", "2" ] },
{ "_id" : "2", "array2" : [ "1", "3" ] },
{ "_id" : "3", "array1" : [ ] },
{ "_id" : "4", "array2" : [ ] },
{ "_id" : "5" },
{ "_id" : "6", "array1" : [ "3", "4" ], "array2" : [ "5" ] }

我希望找到一个查询,可以简单地返回单个数组中的唯一数组值,如下所示:
{"_id":"theID", "result":["1", "2", "3", "4", "5"]}

这个id并不重要。需要注意的是,array1array2、两者都有或都没有都可以出现在一个文档中,甚至可以为空。我尝试了很多聚合和级联查询命令,但都无法得出所需的响应结果。


这并不像我想象中的那么容易。我的想法是先使用$setUnion将两个数组压缩成一个,然后使用$unwind展开结果数组,并使用$group$addToSet来对它们进行分组,但不幸的是,$setUnion只有在文档中同时存在这两个字段时才能正常工作。 - Philipp
1个回答

6
要做到这一点,您需要使用.aggregate()方法,该方法提供了对聚合管道的访问。
管道中的第一个阶段使用$match运算符来过滤掉那些不包含array1array2的文档,使用$exists运算符和点符号表示法。这个运算符减少了要在管道下面处理的文档数量。
下一个阶段是$project,在这里您基本上使用$setUnion返回一个包含任何数组中出现的元素的数组;它还过滤掉其结果中的重复元素。还要注意使用$ifNull运算符,它根据第一个表达式是否为null(这里的表达式为“array1”和“array2”)返回第一个表达式的值或空数组。
从那里开始,您需要使用$unwind运算符对“arrays”字段进行去规范化。
在管道的最后一个阶段,您$group并使用$addToSet累加器运算符,它返回一个唯一值的数组。
db.getCollection('collection').aggregate([
    { "$match": { 
        "$or": [ 
            { "array1.0": { "$exists": true } }, 
            { "array2.0": { "$exists": true } }
        ]
    }}, 
    { "$project": { 
        "arrays": { 
            "$setUnion": [ 
                { "$ifNull": [ "$array1", [] ] },
                { "$ifNull": [ "$array2", [] ] } 
            ] 
        }
    }}, 
    { "$unwind": "$arrays" }, 
    { "$group": { 
        "_id": null, 
        "arrays": { "$addToSet": "$arrays" } 
    }} 
] )

这将产生:

{ "_id" : null, "arrays" : [ "5", "3", "1", "4", "2" ] }

使用 $ifNull$setUnion 中非常重要,否则如果一个数组为空,你将会得到 NULL。 - sidonaldson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接