【问题标题】:Mongo Group and sum with two fieldsMongo Group 和两个字段的总和
【发布时间】:2016-02-22 18:05:08
【问题描述】:

我有如下文件:

{
   "from":"abc@sss.ddd",
   "to" :"ssd@dff.dff",
   "email": "Hi hello"
}

我们如何计算“from and to”或“to and from”的总和计数? 喜欢两个人​​之间的交流吗?

我能够计算一种方式的总和。我想双向求和。

db.test.aggregate([
      { $group: {
         "_id":{ "from": "$from", "to":"$to"},
           "count":{$sum:1} 
         }
      },
      { 
        "$sort" :{"count":-1}
      }
])

【问题讨论】:

  • 我想你已经算过双向总和了。结果可能如下所示:{_id: {from: "a", to: "b"}, count 100} {_id: {from: "b", to: "a"}, count: 1000},双向结果在输出中。
  • @zydcom:不,它没有。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

由于您需要计算 2 个地址之间交换的电子邮件数量,因此可以将统一的 between 字段投影如下:

db.a.aggregate([
    { $match: {
        to: { $exists: true },
        from: { $exists: true },
        email: { $exists: true }
    }}, 
    { $project: {
        between: { $cond: { 
            if: { $lte: [ { $strcasecmp: [ "$to", "$from" ] }, 0 ] }, 
            then: [ { $toLower: "$to" }, { $toLower: "$from" } ], 
            else: [ { $toLower: "$from" }, { $toLower: "$to" } ] }
        } 
    }},
    { $group: {
         "_id": "$between",
         "count": { $sum: 1 } 
    }},
    { $sort :{ count: -1 } }
])

这个例子中的统一逻辑应该很清楚:它是一个按字母顺序排列的两封电子邮件的数组。如果您信任您的数据,$match$toLower 部分是可选的。

示例中使用的运算符的文档:

【讨论】:

  • 你能解释一下$cond的意思吗?
  • 我怀疑我能比在文档中更好地解释它。如果有帮助,我已经添加了链接。
  • 我知道$cond,我想了解你在那里做了什么逻辑。
  • 逻辑简单明了:如果数组[to, from]按字母顺序排序,则between为[to, from],否则为[from, to]。对 2 个元素的数组进行排序非常简单。对于 "from":"abc@sss.ddd", "to" :"ssd@dff.dff""from":"ssd@dff.dff", "to" :"abc@sss.ddd" 对,投影的 between 为:["abc@sss.ddd", "ssd@dff.dff"]
【解决方案2】:

您基本上需要考虑将_id 分组为可能的“to”和“from”值的“数组”,然后当然对它们进行“排序”,以便在每个文档中组合始终在相同的顺序。

作为旁注,我想补充一点“通常”,当我处理这样的消息传递系统时,“to”和“from”发件人/收件人通常都是以数组开头,所以通常构成了该语句的不同变体来源的基础。

首先,针对单个地址的最优化的 MongoDB 3.2 语​​句

db.collection.aggregate([
    // Join in array
    { "$project": {
        "people": [ "$to", "$from" ],
    }},

    // Unwind array
    { "$unwind": "$people" },

    // Sort array
    { "$sort": { "_id": 1, "people": 1 } },

    // Group document
    { "$group": {
        "_id": "$_id",
        "people": { "$push": "$people" }
    }},

    // Group people and count
    { "$group": {
        "_id": "$people",
        "count": { "$sum": 1 }
    }}
]);

这是基础,现在唯一的变化是“人”数组的构造(仅上面的第 1 阶段)。

MongoDB 3.x 和 2.6.x - 数组

{ "$project": {
    "people": { "$setUnion": [ "$to", "$from" ] }
}}

MongoDB 3.x 和 2.6.x - 字段到数组

{ "$project": {
    "people": { 
        "$map": {
            "input": ["A","B"],
            "as": "el",
            "in": {
               "$cond": [
                   { "$eq": [ "A", "$$el" ] },
                   "$to",
                   "$from"
               ]
            }
        }
    }
}}

MongoDB 2.4.x 和 2.2.x - 来自字段

{ "$project": {
    "to": 1,
    "from": 1,
    "type": { "$const": [ "A", "B" ] }
}},
{ "$unwind": "$type" },
{ "$group": {
    "_id": "$_id",
    "people": {
        "$addToSet": {
            "$cond": [
                { "$eq": [ "$type", "A" ] },
                "$to",
                "$from"
            ]
        }
    }
}}

但在所有情况下:

  1. 将所有收件人放入一个不同的数组中。

  2. 将数组排序为一致的顺序

  3. 在“始终按相同顺序”的收件人列表中分组。

遵循它,你就不会出错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-27
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    相关资源
    最近更新 更多