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