【发布时间】:2014-01-08 08:00:51
【问题描述】:
我在 mongodb 中有一个非常大的项目集合,其架构无法更改。简化版如下所示:
{event: { address: {ip: "1.1.1.1", port: 80}}}
{event: { address: {ip: "1.1.1.2", port: 80}}}
{event: { address: [{ip: "1.1.1.1", port: 80}, {ip: "1.1.1.1", port: 443}]}}
{event: { address: [{ip: "1.1.1.1", port: 8080}, {ip: "1.1.1.2", port: 443}]}}
每个事件可能有一个或多个地址。每个地址都有“ip”和“port”。因此,一个“ip”可能会在具有多个地址的事件中重复。
我要做的就是统计每个 ip 地址的事件数并找到排名靠前的 ip 地址。对于上面的例子,首选的结果是:
[ { "ip" : "1.1.1.1", "count" : 3 },
{ "ip" : "1.1.1.2", "count" : 2 } ]
想到的一个查询是这样的:
db.collection.aggregate({$project: {ip: "$event.address.ip"}}, {$group: {_id: "$ip", count: {$sum: 1}}}, {$sort: {count: -1}}, {$limit: 5})
但结果是:
{
"result" : [
{ "_id" : ["1.1.1.1", "1.1.1.2"], "count" : 1 },
{ "_id" : ["1.1.1.1", "1.1.1.1"], "count" : 1 },
{ "_id" : "1.1.1.2", "count" : 1 },
{ "_id" : "1.1.1.1", "count" : 1 } ],
"ok" : 1
}
我不能使用 $unwind,因为每个 IP 地址对于每个事件都应该只计算一次,但有些事件会重复相同的 IP。此外, $unwind 通常不会起作用,因为“地址”并不总是一个数组。有些事件只有一个不是数组的地址,$unwind 会为它们抛出异常。
我尝试了不同的聚合运算符,例如 $group 中的 $addToSet,但都无济于事。
集合非常庞大,我无法先提取应用程序中的所有 ip 地址,然后为每个事件统计事件。
可以用 map/reduce 来完成吗?你有什么建议?
【问题讨论】:
标签: mongodb aggregation-framework