Mongodb Mongo查询具有两级未知父键的嵌套字段值

Mongodb Mongo查询具有两级未知父键的嵌套字段值,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我们使用MongoDB存储时间序列传感器数据,类似于中设计的模式 我们确实在数据查询方面获得了很好的性能。 关于我们的模式设计的解释: “v”是传感器读数的父键,时间使用分和秒转换为嵌套数组。我们使用“m”(分钟)作为子父键,然后使用“s”(秒)作为分钟读取的子键。传感器读数位于“s”级别,其中字段1、字段2、…、字段10作为传感器数据值 现在,我们正在尝试实现一些数据分析工具,并希望通过传感器数据读取值查询数据。有没有一种有效的方法可以从数据中查询,而不必在查询中使用嵌套for循环 例如: 具

我们使用MongoDB存储时间序列传感器数据,类似于中设计的模式

我们确实在数据查询方面获得了很好的性能。 关于我们的模式设计的解释: “v”是传感器读数的父键,时间使用分和秒转换为嵌套数组。我们使用“m”(分钟)作为子父键,然后使用“s”(秒)作为分钟读取的子键。传感器读数位于“s”级别,其中字段1字段2、…、字段10作为传感器数据值

现在,我们正在尝试实现一些数据分析工具,并希望通过传感器数据读取值查询数据。有没有一种有效的方法可以从数据中查询,而不必在查询中使用嵌套for循环

例如:

  • 具有传感器读数的项目:“字段1”>2
  • 具有传感器读数的项目:“字段1”>2“字段3”>5
  • 非常感谢

    这些记录如下面的示例所示

    {
       "_id": ObjectId("5a5dd49f74bbaefd1ac89fc8"),
       "c_id": "1017",
       "c_id_s": NumberInt(1017),
       "c_t": NumberInt(1516096800),
       "type": "hour",
       "v": {
         "m1": {
           "s54": {
             "field1": 7.373158,
             "entry_id": NumberInt(4635),
             "field3": 0.19,
             "field2": NumberInt(88) 
          } 
        },
         "m31": {
           "s54": {
             "field1": 5.981918,
             "entry_id": NumberInt(4637),
             "field3": 0.04 
          },
           "s55": {
             "field2": NumberInt(89),
             "entry_id": NumberInt(4639),
             "field5": NumberInt(-67) 
          } 
        } 
      },
       "entry_id": NumberInt(4639) 
    }, 
    {
       "_id": ObjectId("5a5dd1a174bbaefd1ac89fc1"),
       "c_id": "1024",
       "c_id_s": NumberInt(1024),
       "c_t": NumberInt(1516096800),
       "type": "hour",
       "v": {
         "m3": {
           "s22": {
             "field3": 210.479996,
             "entry_id": NumberInt(30297) 
          },
           "s23": {
             "field1": 3.271534,
             "entry_id": NumberInt(30300),
             "field8": 7.1875,
             "field2": NumberInt(94) 
          } 
        },
         "m8": {
           "s23": {
             "field3": 150.639999,
             "entry_id": NumberInt(30304),
             "field1": 2.948425,
             "field8": 7.125,
             "field2": NumberInt(94) 
          } 
        },
         "m13": {
           "s23": {
             "field3": 99.799995,
             "entry_id": NumberInt(30308),
             "field1": 2.849621,
             "field8": 7.0625,
             "field2": NumberInt(95) 
          } 
        },
         "m18": {
           "s23": {
             "field3": 59.099998,
             "entry_id": NumberInt(30312),
             "field1": 2.681393,
             "field8": 6.9375,
             "field2": NumberInt(95) 
          } 
        },
         "m19": {
           "s8": {
             "field5": NumberInt(-87),
             "entry_id": NumberInt(30313) 
          } 
        } 
      },
       "entry_id": NumberInt(30313) 
    }
    

    Map reduce允许您处理命名键,但聚合是实现高效查询的方法

    对于聚合框架,您必须将数据建模为嵌入文档的数组

    我给了你两个选择。您可以为数据集测试它们,看看哪一个更适合您

    差不多

    "v":[
      {
        "minute":1,
        "seconds":[
          {
            "second":54,
            "data":{
             "field1":7.373158,
             "entry_id":4635,
             "field3":0.19,
             "field2":88
           }
          }
        ]
      },
      {
        "minute":2,
        "seconds":...
      }
    ]
    
    "v":[
      {
        "second":1,
        "data":{
           "field1":7.373158,
           "entry_id":4635,
           "field3":0.19,
           "field2":88
         }
      },
      {
         "second":2,
         "data":...
      }
    ]
    
    现在,您可以轻松查询具有传感器读数的项目:“field1”>2

    或者,您可以按分钟分割文档。差不多

    "v":[
      {
        "minute":1,
        "seconds":[
          {
            "second":54,
            "data":{
             "field1":7.373158,
             "entry_id":4635,
             "field3":0.19,
             "field2":88
           }
          }
        ]
      },
      {
        "minute":2,
        "seconds":...
      }
    ]
    
    "v":[
      {
        "second":1,
        "data":{
           "field1":7.373158,
           "entry_id":4635,
           "field3":0.19,
           "field2":88
         }
      },
      {
         "second":2,
         "data":...
      }
    ]
    
    现在可以查询like(使用v.data.field1上的索引)

    您可以查询具有传感器读数的项目:“field1”>2和“field3”>5

    使用第一结构

    db.col.aggregate(
      [{"$match":{"v":{"$elemMatch":{"seconds": {$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}}}},
      {"$unwind":"$v"}, 
        {"$match":{"v.seconds": {$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}},
      {"$unwind":"$v.seconds"}, 
      {"$project":{"data":"$v.seconds.data"}}]
    )
    
    db.col.aggregate(
      [{"$match":{"v.data":{$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}},
      {"$unwind":"$v"}, 
      {"$match":{"v.data.field1":{"$gt":2},"v.data.field3":{"$gt":5} }},
      {"$project":{"data":"$v.data"}}]
    )
    
    使用第二结构

    db.col.aggregate(
      [{"$match":{"v":{"$elemMatch":{"seconds": {$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}}}},
      {"$unwind":"$v"}, 
        {"$match":{"v.seconds": {$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}},
      {"$unwind":"$v.seconds"}, 
      {"$project":{"data":"$v.seconds.data"}}]
    )
    
    db.col.aggregate(
      [{"$match":{"v.data":{$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}},
      {"$unwind":"$v"}, 
      {"$match":{"v.data.field1":{"$gt":2},"v.data.field3":{"$gt":5} }},
      {"$project":{"data":"$v.data"}}]
    )
    
    Mongo更新3.6

    $match
    与接受聚合表达式的
    $expr
    匹配

    $gt>0
    -用于检查一分钟内所有匹配秒数条件之和是否大于0的聚合表达式

    $objectToArray
    将命名密钥转换为键值对,然后根据输入条件和匹配秒数记录输出
    $filter
    秒数

    db.testcol.aggregate(
    {"$match":{
      "$expr":{
        "$gt":[
          {"$sum":{
            "$map":{
              "input":{"$objectToArray":"$v"},
              "as":"secondsofminute",
              "in":{
                "$size":{
                  "$filter":{
                    "input":{"$objectToArray":"$$secondsofminute.v"},
                    "as":"seconds",
                    "cond":{"$gt":["$$seconds.v.field2",2]}
                  }
                }
              }
            }
          }},
        0]
      }
    }})
    
    Mongo更新3.4-将
    $expr
    替换为
    $redact

    db.col.aggregate(
     {"$redact":{
      "$cond":{
        "if":{
          "$gt":[
            {"$sum":{
              "$map":{
                "input":{"$objectToArray":"$v"},
                "as":"secondsofminute",
                "in":{
                  "$size":{
                    "$filter":{
                      "input":{"$objectToArray":"$$secondsofminute.v"},
                      "as":"seconds",
                      "cond":{"$gt":["$$seconds.v.field2",2]}
                    }
                  }
                }
              }
            }},
            0]
        },
       "then":"$$KEEP",
       "else":"$$PRUNE"
      }
    }})
    

    请举例说明您希望返回的文档的外观。返回的文档可以是与conditions@dnickless返回的文档可以是与条件匹配的整个文档。我目前使用这种方法,但速度很慢:{$and:[{c_id:“415”},{$where:function(){for(this.v中的var key){for(this.v[key]中的var子key]){if(this.v[key][subKey].field1>2{return true;}}}}}}}}}}return false;}}}]}@leon你有什么发现吗?我面临着一个类似的问题。谢谢你的回复,但目前我们不想更改数据存储结构,因为系统已经上线。你建议的结构也有优点和缺点,例如,按分钟和秒排序数据会慢一些。Np。我已经添加了3.6和3.4版本更新。对于较低版本版本您必须使用$where/map REDUCTION我们为客户提供实时数据浏览服务,map REDUCTION实际上不可行。对于低于3.4的版本,恐怕您没有太多选项。服务器升级是您的选项吗?可以升级,查询选项是什么?