说我在我的收藏中有这些文件:
{ 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
中的所有子文档必须在给定的搜索词中)。
答案 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
阶段。