我需要帮助才能使数组元素具有文档中字段(级别)的最大值。然后计算按数组元素字段“bssid”分组的总出现次数。
考虑以下数据
/* 1 */
{
"_id" : "18:59:36:0c:94:a3",
"timestamp" : "1460012567",
"apdata" : [{
"bssid" : "f4:b7:e2:56:e4:20",
"ssid" : "Test Network2",
"level" : -55
}, {
"bssid" : "b8:a3:86:67:03:56",
"ssid" : "Test Network1",
"level" : -76
}]
}
/* 2 */
{
"_id" : "d0:b3:3f:b9:42:38",
"timestamp" : "1460013345",
"apdata" : [{
"bssid" : "f4:b7:e2:56:e4:20",
"ssid" : "Test Network2",
"level" : -65
}, {
"bssid" : "b8:a3:86:67:03:56",
"ssid" : "Test Network1",
"level" : -46
}]
}
/* 3 */
{
"_id" : "d0:b3:3f:b9:42:41",
"timestamp" : "1460013145",
"apdata" : [{
"bssid" : "f4:b7:e2:56:e4:20",
"ssid" : "Test Network2",
"level" : -65
}, {
"bssid" : "b8:a3:86:67:03:56",
"ssid" : "Test Network1",
"level" : -46
}]
}
所需的输出是
{
"bssid" : "f4:b7:e2:56:e4:20",
"ssid" : "Test Network2",
"count" : 1
}, {
"bssid" : "b8:a3:86:67:03:56",
"ssid" : "Test Network1",
"count" : 2
}
每个bssid在整个集合中每个文档的数组中具有最大值的次数。
答案 0 :(得分:1)
如果您有MongoDB 3.2,那么您可以这样做:
db.sample.aggregate([
{ "$project": {
"apdata": {
"$arrayElemAt": [
{ "$filter": {
"input": "$apdata",
"as": "el",
"cond": {
"$eq": [
"$$el.level",
{ "$max": {
"$map": {
"input": "$apdata",
"as": "data",
"in": "$$data.level"
}
}}
]
}
}},
0
]
}
}},
{ "$group": {
"_id": "$apdata.bssid",
"ssid": { "$first": "$apdata.ssid" },
"count": { "$sum": 1 }
}}
])
至少对于MongoDB 2.6,你需要这样做:
db.sample.aggregate([
{ "$unwind": "$apdata" },
{ "$group": {
"_id": "$_id",
"apdata": { "$push": "$apdata" },
"max": { "$max": "$apdata.level" }
}},
{ "$unwind": "$apdata" },
{ "$redact": {
"$cond": {
"if": { "$eq": [ "$apdata.level", "$max" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$group": {
"_id": "$apdata.bssid",
"ssid": { "$first": "$apdata.ssid" },
"count": { "$sum": 1 }
}}
])
对于像这样的MongoDB 2.4或2.2:
db.sample.aggregate([
{ "$unwind": "$apdata" },
{ "$group": {
"_id": "$_id",
"apdata": { "$push": "$apdata" },
"max": { "$max": "$apdata.level" }
}},
{ "$unwind": "$apdata" },
{ "$project": {
"apdata": 1,
"isMax": { "$eq": [ "$apdata.level", "$max" ] }
}},
{ "$match": { "isMax": true } },
{ "$group": {
"_id": "$apdata.bssid",
"ssid": { "$first": "$apdata.ssid" },
"count": { "$sum": 1 }
}}
])
在所有情况下,$max
用于获取每个文档中“数组”中数组的“最大”值,然后您可以使用它来“过滤”数组内容,然后再将其用于{ {3}}。这种方法仅随版本
MongoDB 3.2 :允许$group
直接处理值的“数组”。因此,$max
用于获取"level"
值并找出“max”实际上是什么。
然后$map
可用于返回与“max”值匹配的数组元素,最后$filter
用于返回“仅”(两个可能的“0”) “index”元素作为普通文档。
如果您基本上重复_id
的整个陈述并获得$arrayElemAt
"ssid"
值,则整个过程可以仅在$group
“中完成” ,但要分别用$first
来演示来表示更容易一些。
MongoDB 2.6 :这缺乏更高级的运营商,尤其是$project
能够“直接”在阵列上工作。值得注意的是,首先需要$max
数组,然后才能在原始文档中实际$unwind
,只是为了获得“最大”值。
然后,该过程确实需要您再次$group
,因为您稍后将对数组中的元素进行分组,然后使用$unwind
来过滤内容。这是$redact
的“逻辑”形式,您可以直接将"level"
与早期阶段的计算“max”进行比较。因此,不会删除不是“max”的元素。
MongoDB 2.4 :基本上是相同的逻辑,除了代替$match
,你实际上需要物理$redact
才能在文档中放置一个字段用于使用$project
进行过滤。
所有版本都具有相同的最终$match
,您可以在其中为"apdata.bssid"
提供"ssid"
的路径,并为{ "_id" : "f4:b7:e2:56:e4:20", "ssid" : "Test Network2", "count" : 1 }
{ "_id" : "b8:a3:86:67:03:56", "ssid" : "Test Network1", "count" : 2 }
和db.sample.aggregate([
{ "$group": {
"_id": {
"$arrayElemAt": [
{ "$map": {
"input": {
"$filter": {
"input": "$apdata",
"as": "el",
"cond": {
"$eq": [
"$$el.level",
{ "$max": {
"$map": {
"input": "$apdata",
"as": "data",
"in": "$$data.level"
}
}}
]
}
}
},
"as": "apdata",
"in": {
"bssid": "$$apdata.bssid",
"ssid": "$$apdata.ssid"
}
}},
0
]
},
"count": { "$sum": 1 }
}}
])
的分组边界提供$group
结果一个简单的$first
来计算结果中分组键的出现次数。
一切都返回如下:
_id
实际上,MongoDB 3.2最“高效”的形式如下:
{
"_id" : {
"bssid" : "b8:a3:86:67:03:56",
"ssid" : "Test Network1"
},
"count" : 2
}
{
"_id" : {
"bssid" : "f4:b7:e2:56:e4:20",
"ssid" : "Test Network2"
},
"count" : 1
}
由于化合物{{1}}的形式略有不同,但它只是一个$sum
阶段,没有重复整个过程来查找“max”值的数组元素数据:
{{1}}