MongoDB查询帮助-查询子对象中任意键的值

MongoDB查询帮助-查询子对象中任意键的值,mongodb,Mongodb,我想在此集合上执行一个查询,以确定哪些文档在匹配特定值的内容中有任何键。这可能吗 我有一系列文件,如: { "things": { "thing1": "red", "thing2": "blue", "thing3": "green" } } 编辑:为了简洁起见如果您不知道键是什么,并且需要它是交互式的,那么您需要使用(众所周知的性能挑战)操作符,如(在shell中): db.test.find({$where:function

我想在此集合上执行一个查询,以确定哪些文档在匹配特定值的内容中有任何键。这可能吗

我有一系列文件,如:

{
    "things": {
        "thing1": "red",
        "thing2": "blue",
        "thing3": "green"
    }
}

编辑:为了简洁起见

如果您不知道键是什么,并且需要它是交互式的,那么您需要使用(众所周知的性能挑战)操作符,如(在shell中):

db.test.find({$where:function(){
对于(此.settings中的var字段){
如果(此.settings[field]=“red”)返回true;
}
返回false;
}})
如果您有一个大的集合,这对于您的目的来说可能太慢了,但是如果您的密钥集未知,这是您唯一的选择

MongoDB 3.6更新

现在,您可以使用聚合运算符在不使用
$where
的情况下执行此操作:

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中进行合理的查询

发件人:

致:

然后,您可以索引
“settings.value”
,并执行如下查询:

db.settings.ensureIndex({ "settings.value" : 1})

db.settings.find({ "settings.value" : "blue" })
更改非常简单…,因为它将设置名称和设置值移动到完全可索引的字段,并将设置列表存储为数组


如果您无法更改模式,可以尝试使用,但需要注意的是,这基本上是性能最差的情况,并且无法有效地使用索引。

遗憾的是,前面的答案都没有提到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将返回“object”,这意味着查询将在所有嵌套元素上迭代,并将遍历所有元素,直到找到具有值的键为止

您可以使用嵌套值检查以前的答案,结果将远远超出预期

字符串化整个对象会影响性能,因为它必须逐个迭代所有内存扇区以匹配它们。并在ram内存中以字符串形式创建对象的副本(由于查询使用了更多ram,所以效率低下;由于函数上下文已经加载了对象,所以速度较慢)


查询本身可以处理objectId、string、int和任何您想要的基本javascript类型。

没错,我错读了他的问题,因为他无法更改模型,但是是的,如果可以的话,您希望这样做,以便您的键得到修复。@wiredpririe原始架构存在哪些问题使得集合难以查询/索引?我解释过了。。这些字段不能按原始结构进行索引。您不能对任意键进行索引。假设我想使用mongoose对其中一个值执行更新,如何实现这一点?如果我有一个数组,其中包含
settingB
settingsC
,并带有一个要更新的值,该怎么办。这样做的最有效方式是什么?@TBE-请提出新问题,而不是添加您的问题作为评论。
db.settings.ensureIndex({ "settings.value" : 1})

db.settings.find({ "settings.value" : "blue" })
{$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")
}}