MongoDB 在列表列表中查找值
MongoDB find value in list of lists
我正在使用 MongoDB 搜索包含列表列表的元素,其中列表中的至少一项与搜索参数匹配。
这是我目前拥有的结构示例。
{
"Item 1":{
"data":[
["green", 1]
]
},
"Item 2":{
"data":[
["blue", 9],
["green", 1]
]
}
}
我想在数据列表中搜索所有值为"green"的项目。
我目前有这个:
my_data.find({'data': {'$in': ['green']}})
然而,没有返回任何结果。
您需要对任何查询元素使用 "direct path",并且 "data" 不是您需要在此处搜索的路径的 "top level",而是 "Item 1"或文档中的 "Item 2" 并且 "data" 是它的子元素。
基本情况是使用"dot notation" where the root elements are "known" to at least possibly exist, and also note that the $in
operator is not necessary just to match a value within an array, since MongoDB does not care. But you will need a nested $elemMatch
代替:
db.my_data.find({
"$or": [
{ "Item 1.data": {
"$elemMatch": {
"$elemMatch": { "$eq": "green" }
}
}},
{ "Item 2.data": {
"$elemMatch": {
"$elemMatch": { "$eq": "green" }
}
}}
]
})
没有"wildcards"用于匹配前面路径的一部分,因此需要在$or
条件中说明完整路径以搜索文档中的每个可能路径。
如果写出所有可能的前缀键不切实际,那么您唯一的其他方法是使用 JavaScript 评估和 $where
来确定匹配逻辑:
db.my_data.find(function() {
var doc = this;
delete doc._id;
var matched = false;
for ( k in doc ) {
matched = doc[k].data.some(function(el) {
return el.some(function(inner) {
return inner === "green";
});
});
if (matched) break;
}
return matched;
})
或者该逻辑的一些变体,以实际测试具有 "data" 数组的可能元素以包含您的 "green" 值。这不是一个很好的解决方案,因为 $where
需要对每个文档执行以评估条件,因此不能使用索引来过滤结果。这意味着扫描整个集合,基本上是最慢的方法。
也只是显示 "shell shortcut" 来写,否则 function()
内容只是作为 "string" 提交给 pymongo 或其他语言驱动程序的 $where
的参数,但基本上下文是 JavaScript 在服务器上计算的代码。
更好的办法是更改您的文档,这样您要查询的元素的路径总是一致的。如:
{
"items": [
{ "name": "Item 1", "data": [["green", 1]] },
{ "name": "Item 2", "data": [["blue", 9], ["green", 1]] }
]
}
然后你可以发出这个简单的查询:
db.my_data.find({ "items.data": { "$elemMatch": { "$elemMatch": { "$eq": "green" } } } })
由于 "path" 始终是 "items.data"
这允许仅针对该路径的一个条件来测试所有元素
我正在使用 MongoDB 搜索包含列表列表的元素,其中列表中的至少一项与搜索参数匹配。
这是我目前拥有的结构示例。
{
"Item 1":{
"data":[
["green", 1]
]
},
"Item 2":{
"data":[
["blue", 9],
["green", 1]
]
}
}
我想在数据列表中搜索所有值为"green"的项目。
我目前有这个:
my_data.find({'data': {'$in': ['green']}})
然而,没有返回任何结果。
您需要对任何查询元素使用 "direct path",并且 "data" 不是您需要在此处搜索的路径的 "top level",而是 "Item 1"或文档中的 "Item 2" 并且 "data" 是它的子元素。
基本情况是使用"dot notation" where the root elements are "known" to at least possibly exist, and also note that the $in
operator is not necessary just to match a value within an array, since MongoDB does not care. But you will need a nested $elemMatch
代替:
db.my_data.find({
"$or": [
{ "Item 1.data": {
"$elemMatch": {
"$elemMatch": { "$eq": "green" }
}
}},
{ "Item 2.data": {
"$elemMatch": {
"$elemMatch": { "$eq": "green" }
}
}}
]
})
没有"wildcards"用于匹配前面路径的一部分,因此需要在$or
条件中说明完整路径以搜索文档中的每个可能路径。
如果写出所有可能的前缀键不切实际,那么您唯一的其他方法是使用 JavaScript 评估和 $where
来确定匹配逻辑:
db.my_data.find(function() {
var doc = this;
delete doc._id;
var matched = false;
for ( k in doc ) {
matched = doc[k].data.some(function(el) {
return el.some(function(inner) {
return inner === "green";
});
});
if (matched) break;
}
return matched;
})
或者该逻辑的一些变体,以实际测试具有 "data" 数组的可能元素以包含您的 "green" 值。这不是一个很好的解决方案,因为 $where
需要对每个文档执行以评估条件,因此不能使用索引来过滤结果。这意味着扫描整个集合,基本上是最慢的方法。
也只是显示 "shell shortcut" 来写,否则 function()
内容只是作为 "string" 提交给 pymongo 或其他语言驱动程序的 $where
的参数,但基本上下文是 JavaScript 在服务器上计算的代码。
更好的办法是更改您的文档,这样您要查询的元素的路径总是一致的。如:
{
"items": [
{ "name": "Item 1", "data": [["green", 1]] },
{ "name": "Item 2", "data": [["blue", 9], ["green", 1]] }
]
}
然后你可以发出这个简单的查询:
db.my_data.find({ "items.data": { "$elemMatch": { "$elemMatch": { "$eq": "green" } } } })
由于 "path" 始终是 "items.data"
这允许仅针对该路径的一个条件来测试所有元素