查找子文档数组是给定搜索项的子集的文档

时间:2017-01-05 17:13:15

标签: mongodb mongodb-query aggregation-framework

说我在我的收藏中有这些文件:

{ foo: [ {bar: 1, baz: 2}, {bar: 3, baz: 4} ] }
{ foo: [ {bar: 5, baz: 6}, {bar: 7, baz: 8} ] }

每个文档包含一个子文档数组foo。现在,此查询允许我查找foo[{bar: 1, baz: 2}, {bar: 3, baz: 4}]的超集的所有文档,即所有给定(子)文档都在foo数组中的位置:

db.examples.find({
  $and: [
    { foo: { $elemMatch: { bar: 1, baz: 2 } } },
    { foo: { $elemMatch: { bar: 3, baz: 4 } } }
  ]
})

这会按预期返回第一个文档。

但是,我如何查找文件,foo是给定搜索字词的子集?意思是,我的搜索词是:

[{bar: 1, baz: 2}, {bar: 3, baz: 4}, {bar: 5, baz: 6}]

我希望它匹配集合中的第一个文档,但不是第二个(foo中的所有子文档必须在给定的搜索词中)。

3 个答案:

答案 0 :(得分:2)

您需要使搜索词成为一个看起来像这样的二维数组。

let searchTerms = [ [1, 2], [3, 4], [5, 6] ];

这是因为你知道an object is an unordered set of name/value pairs

从那里你需要使用$redact运算符来执行逻辑$cond ition处理。

此处的条件为$setIsSubset,当"输入"中的元素时,它返回true。数组是searchTerms数组的子集。

$setIsSubset返回true时,您$$KEEP文档并在使用$$PRUNE变量返回false时将其丢弃。

当然$setIsSubset中的第一个表达式需要解析为二维数组,例如" searchTerms"阵列。要做到这一点,您需要使用$map数组运算符,它允许您将表达式应用于" foo"中的每个子文档。阵列。这里的表达式使用版本3.2中的[]运算符new来返回一个二维数组,其中每个子数组中的第一个元素是" bar"的值。最后一个元素是" bar"。

的值
db.collection.aggregate([
    { "$redact": { 
        "$cond": [ 
            { "$setIsSubset": [
                { "$map": {
                    "input": "$foo", 
                    "as": "f", 
                    "in": [ "$$f.bar", "$$f.baz" ]}
                }, 
                searchTerms
            ]}, 
            "$$KEEP", 
            "$$PRUNE" 
        ]
    }}
])

最后,请注意$redact不使用索引。

答案 1 :(得分:2)

$elemMatch的{​​p> $nor选择foo子文档与搜索字词不匹配的所有文档,$not选择foo子文档为子集的文档搜索词。

您也可以使用$nin代替$nor

如果您的子文档不包含搜索字段,则可能需要包含$exist条件。

db.examples.find({
    foo: {
        $not: {
            $elemMatch: {
                $nor: [{bar: 1,baz: 2},{bar: 3,baz: 4}, {bar: 5,baz: 6}]
            }
        }
    }
});

答案 2 :(得分:0)

您可以在汇总管道中使用setIsSubset

db.example.aggregate([
    {
        $project : {
            foo : 1,
            criteria : {
                $literal : [{bar: 1, baz: 2}, {bar: 3, baz: 4}, {bar: 5, baz: 6}]
            }
        }
    },
    {
        $project : {
            foo : 1,
            subset : {
                $setIsSubset : ["$foo", "$criteria"]
            }
        }
    },
    {
        $match : {
            subset : true
        }
    },
    {
        $project : {
            foo : 1
        }
    }
])

输出:

{ "_id" : ..., "foo" : [ { "bar" : 1, "baz" : 2 }, { "bar" : 3, "baz" : 4 } ] }

注意:您可以在可能使用索引的第一个$match之前使用$project阶段。

相关问题