我想对此集合执行查询,以确定哪些文档在与某个值匹配的事物中具有任何键。这可能吗?
我有一系列文件,例如:
{
"things": {
"thing1": "red",
"thing2": "blue",
"thing3": "green"
}
}
编辑:为了简洁
我想对此集合执行查询,以确定哪些文档在与某个值匹配的事物中具有任何键。这可能吗?
我有一系列文件,例如:
{
"things": {
"thing1": "red",
"thing2": "blue",
"thing3": "green"
}
}
编辑:为了简洁
如果您不知道键是什么并且您需要它是交互式的,那么您需要$where
像这样(在 shell 中)使用(臭名昭著的性能挑战)运算符:
db.test.find({$where: function() {
for (var field in this.settings) {
if (this.settings[field] == "red") return true;
}
return false;
}})
如果您有大量集合,这可能对您的目的来说太慢,但如果您的密钥集未知,这是您唯一的选择。
MongoDB 3.6 更新
您现在可以在不$where
使用$objectToArray
聚合运算符的情况下执行此操作:
db.test.aggregate([
// Project things as a key/value array, along with the original doc
{$project: {
array: {$objectToArray: '$things'},
doc: '$$ROOT'
}},
// Match the docs with a field value of 'red'
{$match: {'array.v': 'red'}},
// Re-project the original doc
{$replaceRoot: {newRoot: '$doc'}}
])
我建议更改架构,以便您实际上可以在 MongoDB 中进行合理的查询。
从:
{
"userId": "12347",
"settings": {
"SettingA": "blue",
"SettingB": "blue",
"SettingC": "green"
}
}
至:
{
"userId": "12347",
"settings": [
{ name: "SettingA", value: "blue" },
{ name: "SettingB", value: "blue" },
{ name: "SettingC", value: "green" }
]
}
然后,您可以索引"settings.value"
,并执行如下查询:
db.settings.ensureIndex({ "settings.value" : 1})
db.settings.find({ "settings.value" : "blue" })
更改确实很简单……因为它将设置名称和设置值移动到完全可索引的字段,并将设置列表存储为数组。
如果您无法更改架构,您可以尝试@JohnnyHK的解决方案,但请注意,就性能而言,这基本上是最差的情况,并且无法有效地处理索引。
可悲的是,以前的答案都没有解决 mongo 可以在数组或嵌套对象中包含嵌套值的事实。
这是正确的查询:
{$where: function() {
var deepIterate = function (obj, value) {
for (var field in obj) {
if (obj[field] == value){
return true;
}
var found = false;
if ( typeof obj[field] === 'object') {
found = deepIterate(obj[field], value)
if (found) { return true; }
}
}
return false;
};
return deepIterate(this, "573c79aef4ef4b9a9523028f")
}}
由于在数组或嵌套对象上调用 typeof 将返回“对象”,这意味着查询将遍历所有嵌套元素并遍历所有元素,直到找到具有值的键。
您可以使用嵌套值检查以前的答案,结果将远非预期。
对整个对象进行字符串化会影响性能,因为它必须逐个遍历所有内存扇区以尝试匹配它们。并在 ram 内存中创建对象的副本作为字符串(由于查询使用更多的 ram 和由于函数上下文已经加载了对象而导致效率低下)。
查询本身可以使用 objectId、string、int 和您希望的任何基本 javascript 类型。