数据库中的示例数据如下所示:
{
'data':
[
'Log':
{
'IP':['8.8.8.8','8.8.4.4'],
'URL':['www.google.com']
'Hash' ['d2a12319bf1221ce7681928cc']
},
'Log':
{
'IP':['1.2.3.4'],
'URL':['www.cnn.com']
'Hash' []
},
]
}
我正在尝试从上面的日志列表中聚合唯一的IP,URL和Hash列表。我当前的查询看起来像这样:
db.loglist.aggregate([{'$match':{'data.Log':{'$exists':true}}},
{'$unwind':'$data'},
{'$unwind':'$data.Log.URL'},
{'$unwind':'$data.Log.Hash'},
{'$unwind':'$data.Log.IP'},
{'$group':{'_id':'$ioc',
'FHList':{'$addToSet':'$data.Log.Hash'},
'URLList':{'$addToSet':'$data.Log.URL'},
'IPList':{'$addToSet':'$data.Log.IP'}}
}])
如果对于每个日志,三个数组中的每个数组中至少有一个元素,则效果很好。但是,当任何一个日志中出现空数组时。 Mongo为整个查询返回空。我发现它是来自几个类似帖子的$ unwind的默认行为。但是,使用$ unwind的标准方法是什么,如果说我们没有结果" Hash",我们仍然可以保留" IP"和" URL"。
提前感谢您的回答。
答案 0 :(得分:1)
$cond
运算符是这里的主要帮助器,通过测试来查看数组是否为空,并将其替换为另一个值以便稍后过滤:
db.loglist.aggregate([
{"$match":{"data.Log":{"$exists":true}}},
{"$unwind":"$data"},
{ "$project": {
"ioc": 1,
"data": {
"Log": {
"IP": { "$cond": [
{ "$ne": [ "$IP", [] ] },
"$IP",
[false]
]},
"URL": { "$cond": [
{ "$ne": [ "$URL", [] ] },
"$URL",
[false]
]},
"Hash": { "$cond": [
{ "$ne": [ "$Hash", [] ] },
"$Hash",
[false]
]}
}
}
}}
{"$unwind":"$data.Log.URL"},
{"$unwind":"$data.Log.Hash"},
{"$unwind":"$data.Log.IP"},
{"$group":{
"_id":"$ioc",
"FHList":{"$addToSet":"$data.Log.Hash"},
"URLList":{"$addToSet":"$data.Log.URL"},
"IPList":{"$addToSet":"$data.Log.IP"}
}},
{ "$project": {
"FHList":{ "$setDifference": ["$FHList", [false]] },
"URLList":{ "$setDifference": ["$URList", [false]] },
"IPList":{ "$setDifference": ["$IPList", [false]] }
}}
])
一旦它构建了它,就会过滤掉不需要的值。
如果您的MongoDB版本低于2.6并且您没有$setDifference
,那么您可以在再次展开后进行过滤,假设此处没有结果数组是空的:
db.loglist.aggregate([
{"$match":{"data.Log":{"$exists":true}}},
{"$unwind":"$data"},
{ "$project": {
"ioc": 1,
"data": {
"Log": {
"IP": { "$cond": [
{ "$ne": [ "$IP", [] ] },
"$IP",
[false]
]},
"URL": { "$cond": [
{ "$ne": [ "$URL", [] ] },
"$URL",
[false]
]},
"Hash": { "$cond": [
{ "$ne": [ "$Hash", [] ] },
"$Hash",
[false]
]}
}
}
}}
{"$unwind":"$data.Log.URL"},
{"$unwind":"$data.Log.Hash"},
{"$unwind":"$data.Log.IP"},
{"$group":{
"_id":"$ioc",
"FHList":{"$addToSet":"$data.Log.Hash"},
"URLList":{"$addToSet":"$data.Log.URL"},
"IPList":{"$addToSet":"$data.Log.IP"}
}},
{ "$unwind": "$FHList" },
{ "$match": { "FHList": { "$ne": false } }},
{ "$unwind": "$URLList" },
{ "$match": { "URLList": { "$ne": false } }},
{ "$unwind": "$IPList" },
{ "$match": { "IPList": { "$ne": false } }},
{ "$group": {
"_id": "$_id",
"FHList":{ "$addToSet":"$FHList" },
"URLList":{ "$addToSet":"$URLList" },
"IPList":{ "$addToSet":"$IPList" }
}}
])
如果您的分组数组是空的,那么在第二种形式中它仍然很棘手但仍然可能。