$ project MongoDB Aggregation中的不同项目

 天呀你呀_778 发布于 2023-02-05 11:49

我在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完成.你会建议什么?

1 个回答
  • 虽然可以使用MapReduce完成,但聚合框架会更快.你需要为你的计划添加两个步骤 - 1)你需要"规范化"格式,以便地址始终是一个数组,2)然后你需要$展开该数组,按_id,ip分组以摆脱重复和然后通过ip分组以获得您需要的计数.

    规范化数组和非数组是很棘手的,但可以使用前后两个投影来完成$unwind.

    var p1 = { "$project" : {
            "array" : {
                "$cond" : [
                    {
                        "$eq" : [
                            "$address.0",
                            [ ]
                        ]
                    },
                    "$address",
                    [
                        null
                    ]
                ]
            },
            "notarray" : {
                "$cond" : [
                    {
                        "$ne" : [
                            "$address.0",
                            [ ]
                        ]
                    },
                    "$address",
                    [
                        null
                    ]
                ]
            },
            "isArray" : {
                "$eq" : [
                    "$address.0.ip",
                    [ ]
                ]
            }
        }
    };
    var u = { "$unwind" : "$array" };
    var p2 = { "$project" : {
            "address" : {
                "$cond" : [
                    "$isArray",
                    "$array",
                    "$notarray"
                ]
            }
        }
    };
    

    相比之下,这两个$group阶段很简单:

    var g1 = { "$group" : { "_id" : { "_id" : "$_id", "ip" : "$address.ip" } } };
    var g2 = { "$group" : { "_id" : "$_id.ip", "count" : { "$sum" : 1 } } };
    

    这是我的示例数据:

    > db.coll.find()
    { "_id" : ObjectId("52cd0badba17f3b7ed212575"), "address" : { "ip" : "1.1.1.1" } }
    { "_id" : ObjectId("52cd0bc4ba17f3b7ed212576"), "address" : [  {  "ip" : "1.1.1.1" },  {  "ip" : "1.1.1.1" } ] }
    { "_id" : ObjectId("52cd0bc9ba17f3b7ed212577"), "address" : [  {  "ip" : "1.1.1.1" },  {  "ip" : "1.1.1.2" } ] }
    

    这是聚合及其输出:

    > db.coll.aggregate(p1, u, p2, g1, g2)
    { "_id" : "1.1.1.1", "count" : 3 }
    { "_id" : "1.1.1.2", "count" : 1 }
    

    2023-02-05 11:51 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有