【问题标题】:Grouping different amounts together in MongoDB在 MongoDB 中将不同的金额分组在一起
【发布时间】:2017-10-22 13:22:50
【问题描述】:

如果我有一组对象,每个对象都有相同的描述,但数量不同。

{

    {
    "_id": "101",
    "description": "DD from my employer1",
    "amount": 1000.33
    },
    {
    "_id": "102",
    "description": "DD from my employer1",
    "amount": 1000.34
    },
    {
    "_id": "103",
    "description": "DD from my employer1",
    "amount": 1000.35
    },
    {
    "_id": "104",
    "description": "DD from employer1",
    "amount": 5000.00
    },
    {
    "_id": "105",
    "description": "DD from my employer2",
    "amount": 2000.33
    },
    {
    "_id": "106",
    "description": "DD from my employer2",
    "amount": 2000.33
    },
    {
    "_id": "107",
    "description": "DD from my employer2",
    "amount": 2000.33
    }

}

下面,我可以使用描述对它们进行分组:

{

    {
        "$group": {
            "_id": {
                "description": "$description"
            },
            "count": {
                "$sum": 1
            },
            "_id": {
                "$addToSet": "$_id"
            }
        }
    },
    {
        "$match": {
            "count": {
                "$gte": 3
            }
        }
    }

}

有没有办法将组中的所有金额都包含在内(_ids:101、102和103加上105,106,107)即使它们有很小的差异,但不包括奖金金额,其中上面的示例是_id 104?

我不相信它可以在小组赛阶段完成,但有什么可以在稍后阶段完成,可以将 _ids 101、102 和 103 组合在一起并排除 _id 104。基本上,我希望 MongoDB忽略 101、102、103 中的微小差异并将它们组合在一起,因为它们是来自同一雇主的薪水。

我一直在使用 $stdDevPop,但无法得出一个可靠的公式。

我正在寻找仅包含 _id 的简单数组输出。

{ “结果”: [ "101", "102", "103", "105", "106", “107” ] }

【问题讨论】:

  • 您可以通过对“数量”进行一些数学运算来进行分组,即四舍五入到 1000 和 $push 匹配的 _id 值到一个数组。 但是,目前您的“金额”值是“字符串”。因此,您要么通过转换为数值来修复该数据,要么接受 mapReduce 的 JavaScript 评估。聚合框架运算符不能将字符串转换为数字。但是 JavaScript 可以。不过,您“应该”真正修复您的数据。
  • 值是数字。错误地显示为字符串。
  • @NeilLunn 谢谢。我使用了 $trunc,然后按描述和截断的值分组,它正在做我想做的事情。
  • 其实你刚刚写完答案。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

您可以通过对“数量”进行一些数学运算来将其向下舍入到最接近的 1000 并将其用作分组 _id

db.collection.aggregate([
  { "$group": {
      "_id": {
        "$subtract": [
           { "$trunc": "$amount" },
           { "$mod": [
             { "$trunc": "$amount" }, 
             1000
           ]}
         ]
      },
      "results": { "$push": "$_id" }
  }},
  { "$redact": {
    "$cond": {
      "if": { "$gt": [ { "$size": "$results" }, 1 ] },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }},
  { "$unwind": "$results" },
  { "$group": {
    "_id": null,
    "results": { "$push": "$results" }
  }}
])

如果您的 MongoDB 早于 3.2,那么您只需要使用带有 $mod 的长格式 $trunc 正在做的事情。如果您的 MongoDB 早于 2.6,那么您将使用 $match 而不是 $redact。因此,在较长的形式中,这是:

db.collection.aggregate([
  { "$group": {
      "_id": {
        "$subtract": [
           { "$subtract": [
             "$amount",
             { "$mod": [ "$amount", 1 ] }
           ]},
           { "$mod": [
             { "$subtract": [
               "$amount",
               { "$mod": [ "$amount", 1 ] }
             ]},
             1000
           ]}
         ]
      },
      "results": { "$push": "$_id" },
      "count": { "$sum": 1 }
  }},
  { "$match": { "count": { "$gt": 1 } } },
  { "$unwind": "$results" },
  { "$group": {
    "_id": null,
    "results": { "$push": "$results" }
  }}
])

无论哪种方式,输出都只是 _id 值,其数量分组到边界,计数不止一次。

{ "_id" : null, "results" : [ "105", "106", "107", "101", "102", "103" ] }

您可以在其中添加$sort,也可以在客户端代码中对结果数组进行排序。

【讨论】:

  • @NeilLune,谢谢,我正在使用 3.4,所以顶部看起来效果很好。我所做的唯一修改是在 $unwind 之前添加结果的 $project,因为 $unwind 没有运行。
  • @Pablo.K 你一定做了一些不同的事情,因为$group 中的行在这里"results": { "$push": "$_id" } 创建了一个数组。两者之间唯一的另一个语句是$redact,它不会以任何方式修改文档,而只是删除任何不符合条件的文档。 “所有版本”兼容列表中的 $match 也是如此。
  • @Pablo.K 如果你有新问题,那么Ask a new Question。一旦给出答案,您不应在此处更改您的问题。 StackOverflow 不是一个线程讨论论坛,而是一个提交不同问题和答案的地方。因此,不要更改现有问题并留下 cmets。 Ask the Question 而不是
【解决方案2】:
db.yourDBNameHere.aggregate( [
  { $match: { "amount" : { $lt : 5000 } } },
  { $project: { _id: 1 } },
])

这将只获取每笔少于 5000 美元的交易的 ID。

【讨论】:

  • 谢谢。然而,有没有办法让它更具动态性,而不是硬编码 5000 的数量?
  • @Pablo.K 您希望条件是什么? MongoDB 有很多数学运算符,那么您希望它在什么条件下排除金额?
  • 试图排除高于 5000 的异常值。这是我的主要目标
  • 匹配语句已经这样做了,它只会匹配数量小于 5000 的条目。如果您希望能够更改该数量是多少,可以使用变量设置查询跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 2014-10-21
相关资源
最近更新 更多