MongoDB:在子文档中查找带有键的文档

ste*_*nci 2 mongodb

$in运营商可与阵列。

字典有等价物吗?

以下代码创建两个测试文档,并在数组文档中查找包含所列值之一的文档,但未在子文档中查找包含相同值的文档。

> use test
> db.stuff.drop()
> db.stuff.insertMany([{lst:['a','b'],dic:{a:1,b:2}},{lst:['a','c'],dic:{a:3,c:4}}])
{
        "acknowledged" : true,
        "insertedIds" : [
                ObjectId("595bbe8b3b0518bcca4b1530"),
                ObjectId("595bbe8b3b0518bcca4b1531")
        ]
}
> db.stuff.find({lst:{$in:['b','c']}},{_id:0})
{ "lst" : [ "a", "b" ], "dic" : { "a" : 1, "b" : 2 } }
{ "lst" : [ "a", "c" ], "dic" : { "a" : 3, "c" : 4 } }
> db.stuff.find({dic:{$in:['b','c']}},{_id:0})
> 
Run Code Online (Sandbox Code Playgroud)

编辑(响应下面的答案)

使用下面答案中建议的列表会阻止我找到所需的元素。例如,insertMany在本问题和答案中同时执行上述内容后,可以使用字典完成以下操作,而不是使用列表(或者我是否遗漏了什么?):

> x=db.stuff.findOne({lst:{$in:['b','c']}},{_id:0})
{ "lst" : [ "a", "b" ], "dic" : { "a" : 1, "b" : 2 } }
> x
{ "lst" : [ "a", "b" ], "dic" : { "a" : 1, "b" : 2 } }
> x.dic.a
1
> x.dic.b
2
Run Code Online (Sandbox Code Playgroud)

A. *_*vis 5

对于子文档,没有完全等同于 $in 的内容。您可以将 $exists 查询运算符与 $or 结合使用:

db.stuff.find({$or:[
    {'dic.b': {$exists: true}},
    {'dic.c': {$exists: true}}
]})
Run Code Online (Sandbox Code Playgroud)

但是,推荐的方法是更改​​架构,以便将键和值更改为{key: "key", value: 123}子文档数组:

db.stuff.insertMany([
   {dic: [{key: 'a', value: 1}, {key: 'b', value: 2}]},
   {dic: [{key: 'a', value: 3}, {key: 'c', value: 4}]}
])
Run Code Online (Sandbox Code Playgroud)

然后您可以使用 $in 查找具有某些键的文档:

db.stuff.find({'dic.key': {$in: ['a', 'b']}})
Run Code Online (Sandbox Code Playgroud)

这个新模式的特别好处是您可以为 $in 查询使用索引:

db.stuff.createIndex({'dic.key': 1})
Run Code Online (Sandbox Code Playgroud)

正如您在上面指出的那样,一个缺点是简单的元素访问x.dic.a不再有效。您需要用您的语言进行一些编码。例如在 Javascript 中:

> var doc = {dic: [{key: 'a', value: 3}, {key: 'c', value: 4}]}
> function getValue(doc, key) {
...   return doc.dic.filter(function(elem) {
...     return elem.key == key;
...   })[0].value;
... }
> getValue(doc, "a")
3
> getValue(doc, "c")
4
Run Code Online (Sandbox Code Playgroud)