【问题标题】:MongoDB Query Help - query on values of any key in a sub-objectMongoDB 查询帮助 - 查询子对象中任何键的值
【发布时间】:2013-11-17 02:59:28
【问题描述】:

我想对该集合执行查询,以确定哪些文档在与某个值匹配的事物中具有任何键。这可能吗?

我有一组文档,例如:

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

编辑:为了简洁

【问题讨论】:

    标签: mongodb


    【解决方案1】:

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

    db.test.find({$where: function() { 
        for (var field in this.settings) { 
            if (this.settings[field] == "red") return true;
        }
        return false;
    }})
    

    如果您的集合很大,这可能对您的目的来说太慢,但如果您的密钥集未知,这是您唯一的选择。

    MongoDB 3.6 更新

    您现在可以使用 $objectToArray 聚合运算符在不使用 $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'}}
    ])
    

    【讨论】:

      【解决方案2】:

      我建议更改架构,以便您实际上可以在 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" })
      

      更改真的很简单......因为它将设置名称和设置值移动到完全可索引的字段,并将设置列表存储为数组。

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

      【讨论】:

      • 对,我误读了他的问题,因为他无法更改模型,但是是的,如果可以的话,你会想要做这样的事情来修复你的密钥。
      • @WiredPrairie 原始模式存在哪些问题使集合难以查询/索引?
      • 我解释说 .. 这些字段无法使用原始结构进行索引。您不能对任意键进行索引。
      • 可以说我想使用猫鼬对其中一个值执行更新,我该如何实现?如果我有一个包含 settingBsettingsC 的数组,其中包含要更新的值。这样做的必须有效的方法是什么?
      • @ekkis - 遇到了这个,stackoverflow.com/questions/19868016/…
      【解决方案3】:

      遗憾的是,之前的答案都没有解决 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 类型。

      【讨论】:

        猜你喜欢
        • 2017-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多