当前位置: 首页 > 知识库问答 >
问题:

$Project MongoDB聚合中的非重复项

贡念
2023-03-14

我在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" : "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
}

集合非常大,我无法首先提取应用程序中的所有ip地址,然后计算每个ip地址的事件。

这能用地图/缩小吗。你有什么建议?

共有1个答案

蒯慈
2023-03-14

虽然这可以通过MapReduce完成,但聚合框架将更快。您需要在计划中添加两个步骤-1)您需要“规范化”格式,使address始终是一个数组,2)然后您需要$unwind该数组,group by_id,ip以消除重复项,然后group by 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 }
 类似资料:
  • 问题内容: 我有一个非常庞大的查询,其最简单的形式如下所示: 我需要再添加一个条件,该条件可以让我获得每个代表的应用程序日期不为空的用户数(例如:rep 1具有3个用户的应用程序日期已填写),并将其分配给类别(由于3个用户,rep是某个状态类别)。看起来像这样: 但是,如果我只是将其添加到select语句中,则所有代表将变为status1,因为sum()是在所有使用申请日期的顾问程序上完成的: 您

  • 我想通过聚合pyspark数据帧来分组,同时基于此数据帧的另一列删除重复项(保留最后一个值)。 总之,我想将dropDuplicates应用于GroupeData对象。所以,对于每个组,我只能动态地保留一行。 对于下面的数据帧,直接的组聚合是: 导致以下数据帧: 我希望聚合只使用每个的最新状态。在这种情况下,已在更新为,因此当时,所有基本时间戳大于的聚合应仅对列功能使用此状态。预期的聚合数据帧是:

  • 我正在尝试设置一个搜索查询,该查询应通过多级嵌套字段复合聚合集合,并从该集合中提供一些子聚合指标。我能够按预期使用其存储桶获取复合聚合,但所有存储桶的子聚合指标都带有。我不确定我是否未能正确指出子聚合应考虑哪些字段,或者它是否应放置在查询的不同部分中。 我的收藏看起来类似于以下内容: 贝娄,你可以找到我已经尝试了。尽管所有文档都有一个设置的点击值,但所有存储桶都带有点击总数。 到目前为止,我的回应

  • 我使用复合和术语聚合来获得基于给定字段的分组结果。我还使用基数聚合来获取聚合桶的总计数。 下面是我发送的请求查询,以获得相应的响应: 请求: 答复: 我使用Kibana检查查询,它对我来说很好。 但是,我不确定如何在我的NEST对象语法中使用这个基数聚合器。 这是我的代码: 我将非常感谢任何帮助。

  • 任何人都可以给出代码示例来显示聚合和组合之间的区别。我已经阅读了这篇文章,但不明白它们在代码上有何不同。 请通过代码显示差异。

  • 我有一个数据帧的值,如: 我想得到每个人不同行动的数量。这一点我可以通过