【问题标题】:How to query a dynamic key - mongodb schema design如何查询动态键-mongodb架构设计
【发布时间】:2013-12-03 15:48:18
【问题描述】:

我有以下文件:

{
    _id     : 1,

    key1    : {
                  samekeyA : "value1",
                  samekeyB : "value2"
              },

    key2 :    {
                  samekeyA : "value3",
                  samekeyB : "value4"
              },

    key3 :    {
                  samekeyA : "value5",
                  samekeyB : "value6"
              }  
}

以上;给出key1、key2 和key3 以证明我不知道完整的密钥,除了它的前缀;但是我知道的内部键samekeyA 和samekeyB。我需要这样的查询:db.coll.find({"key*.samekeyA":"value1"})。

我认为没有一种 mongo 方式 - 正则表达式键查询? - 来实现这一点,所以有什么想法吗?我应该改造我的文档-tree-吗?

【问题讨论】:

    标签: mongodb database-design aggregation-framework


    【解决方案1】:

    使用 MongoDB 3.4.4 及更新版本:

    db.coll.aggregate([
        { "$replaceRoot": {
            "newRoot": {
                "$arrayToObject": {
                    "$filter": {
                        "input": { "$objectToArray": "$$ROOT" },
                        "as": "el",
                        "cond": {
                            "$eq": [
                                "$$el.v.samekeyA",
                                "value1"
                            ]
                        }
                    }
                }
            }   
        } }
    ])
    

    上述管道将产生最终输出

    {
        "key1" : {
            "samekeyA" : "value1",
            "samekeyB" : "value2"
        }
    }
    

    说明

    可以分解管道以显示每个操作员的结果。

    $objectToArray

    $objectToArray 使您能够使用动态键转换根文档 (由系统变量 $$ROOT 表示)到一个数组中,该数组包含原始文档中每个字段/值对的元素。返回数组中的每个元素都是一个包含两个字段 k 和 v 的文档。 在 $project 阶段仅使用操作员运行管道

    db.coll.aggregate([
        { "$project": {
            "keys": { "$objectToArray": "$$ROOT" }
        } }
    ])
    

    产量

    {
        "_id" : 1,
        "keys" : [ 
            {
                "k" : "_id",
                "v" : 1
            }, 
            {
                "k" : "key1",
                "v" : {
                    "samekeyA" : "value1",
                    "samekeyB" : "value2"
                }
            }, 
            {
                "k" : "key2",
                "v" : {
                    "samekeyA" : "value3",
                    "samekeyB" : "value4"
                }
            }, 
            {
                "k" : "key3",
                "v" : {
                    "samekeyA" : "value5",
                    "samekeyB" : "value6"
                }
            }
        ]
    }
    

    $filter

    $filter 运算符充当由 $objectToArray 运算符生成的数组的过滤机制,通过选择要返回的数组的子集来工作指定的条件 成为您的查询。

    考虑以下管道,它返回与条件 { "samekeyA": "value1" } 匹配的键/值对数组

    db.coll.aggregate([
        { "$project": {
            "keys": { 
                "$filter": {
                    "input": { "$objectToArray": "$$ROOT" },
                    "as": "el",
                    "cond": {
                        "$eq": [
                            "$$el.v.samekeyA",
                            "value1"
                        ]
                    }
                }  
            }
        } }
    ])
    

    产生

    {
        "_id" : 1,
        "keys" : [ 
            {
                "k" : "key1",
                "v" : {
                    "samekeyA" : "value1",
                    "samekeyB" : "value2"
                }
            }
        ]
    }
    

    $arrayToObject

    这将从

    转换上面的过滤数组
    [ 
        {
            "k" : "key1",
            "v" : {
                "samekeyA" : "value1",
                "samekeyB" : "value2"
            }
        }
    ]
    

    到带有动态键的原始文档

    {
        "key1" : {
            "samekeyA" : "value1",
            "samekeyB" : "value2"
        }
    }
    

    所以运行管道

    db.coll.aggregate([
        { "$project": {
            "key": {
                "$arrayToObject": {
                    "$filter": {
                        "input": { "$objectToArray": "$$ROOT" },
                        "as": "el",
                        "cond": {
                            "$eq": [
                                "$$el.v.samekeyA",
                                "value1"
                            ]
                        }
                    }
                }
            }   
        } }
    ])
    

    会产生

    {
        "_id" : 1,
        "key" : {
            "key1" : {
                "samekeyA" : "value1",
                "samekeyB" : "value2"
            }
        }
    }
    

    $replaceRoot

    这会将过滤后的动态密钥文档提升到顶层并替换所有其他字段。该操作将替换输入文档中的所有现有字段,包括_id 字段。

    基本上这会改变上述文档

    {
        "_id" : 1,
        "key" : {
            "key1" : {
                "samekeyA" : "value1",
                "samekeyB" : "value2"
            }
        }
    }
    

    到想要的最终输出

    {
        "key1" : {
            "samekeyA" : "value1",
            "samekeyB" : "value2"
        }
    }
    

    【讨论】:

      【解决方案2】:

      我建议重构模型。

      {
          _id     : 1,
      
          data: [   {
                        key      : "key1",
                        samekeyA : "value1",
                        samekeyB : "value2"
                    },
      
                    {
                        key      : "key2",
                        samekeyA : "value3",
                        samekeyB : "value4"
                    },
      
                    {
                        key      : "key3",
                        samekeyA : "value5",
                        samekeyB : "value6"
                    }  
          ]
      }
      

      还有查询:

      db.col.find({"data.samekeyA": "value1"})
      

      目前(将来也可能)无法在字段名中使用通配符查询 MongoDB 集合(感谢@gWiz)。

      【讨论】:

      • 也就是说:不,MongoDB 没有任何这样的查询运算符可以让您将字段与正则表达式进行匹配。
      猜你喜欢
      • 2018-07-04
      • 1970-01-01
      • 2012-08-25
      • 2011-05-25
      • 1970-01-01
      • 2011-11-20
      • 2015-04-21
      • 2011-12-28
      相关资源
      最近更新 更多