【问题标题】:Grouping and summing an embedded array by month按月对嵌入式数组进行分组和求和
【发布时间】:2019-02-14 08:15:05
【问题描述】:

我有以下架构:

_id 
dates : 
    date :
       year
       month
       day
other unrelated fields

我已经对每个 _id 进行了分组,以便日期包含多个日期对象(其中包含年、月、日)。我现在想按年和月对每个日期对象进行分组,以便获得与年和月相对应的日期数。例如,如果我有以下文件:

_id : 124567789554
dates : 
    date : 
        year : 2018
        month : 9
        day : 1
    date : 
        year : 2018
        month : 9
        day : 2
    date : 
        year : 2018
        month : 9
        day : 3
    date : 
        year : 2018
        month : 10
        day : 1

我想要的输出是:

_id : 124567789554
dates : 
    date : 
        year : 2018
        month : 9
        count : 3
    date : 
        year : 2018
        month : 10
        count : 1

我该怎么做?

编辑:对于一些额外的上下文,我首先必须按 personId 分组。最初的架构如下所示:

_Id (automatically generated by mongoDB)
personId 
date

有多个相同personId的行,对应一个日期。我必须首先将_Id = personId 分组,然后将日期聚合在一起。我怎样才能同时做这两个?我当前的查询:

{
  _id: "$personId",
  dates: {
    $addToSet: "$date"
  },
  other unrelated fields
}

【问题讨论】:

    标签: mongodb nosql mongodb-query aggregation-framework nosql-aggregation


    【解决方案1】:

    如果您将字段保持为BSON Date 格式,则可以使用group aggregation 轻松实现。

    来自 Mongo Document 的一个非常相似的代码示例:

    db.sales.aggregate(
       [
          {
            $group : {
               _id : { month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } },
               totalPrice: { $sum: { $multiply: [ "$price", "$quantity" ] } },
               averageQuantity: { $avg: "$quantity" },
               count: { $sum: 1 }
            }
          }
       ]
    )
    

    结果:

    { "_id" : { "month" : 3, "day" : 15, "year" : 2014 }, "totalPrice" : 50, "averageQuantity" : 10, "count" : 1 }
    { "_id" : { "month" : 4, "day" : 4, "year" : 2014 }, "totalPrice" : 200, "averageQuantity" : 15, "count" : 2 }
    { "_id" : { "month" : 3, "day" : 1, "year" : 2014 }, "totalPrice" : 40, "averageQuantity" : 1.5, "count" : 2 }
    

    【讨论】:

    • 我认为我的有点不同,因为我首先必须按 personId 分组。开始的模式如下所示:_id, personId, date, ... 由于有多个日期对应一个人,因此 personId 的多行具有对应的日期。
    【解决方案2】:

    使用 $group 按人员 ID、月份和年份分组并计算匹配数,然后使用 $group 收集具有年和月份的所有日期并计算每个人员 ID。

    db.colname.aggregate([
      {"$group":{
        "_id":{"personId":"$personId","year":"$date.year","month":"$date.month"},
        "count":{"$sum":1}
      }},
      {"$group":{
        "_id":"$_id.personId",
        "dates":{"$push":{"year":"$_id.year","month":"$_id.month","count":"$count"}}
      }}
    ])
    

    【讨论】:

    • 此解决方案有效,谢谢!我怎样才能访问日期数组中的对象呢?我正在尝试 $match 计数以创建一个新的布尔字段,如果任何月份的任何计数大于 5,则该字段返回 true。
    • Yw。在 $push 的 count 字段后添加"countgt5":{"$cond":[{"$gt":["$count",5]},true,false]}
    • 这会将真/假字段添加到年/月的每个计数中,但如果任何年/月的计数大于 5,我希望此字段返回真/假(所以只有每个文档的一个字段,而不是每个年/月计数的一个字段)
    • 啊。错过了那部分。在 $group 阶段之后添加以下阶段。 {"$addFields":{"countgt5":{"$gt":[{"$size":{"$filter":{"input":"$dates","cond":{"$gt":["$$this.count",5]}}}},0]}}}
    • 你是神。非常感谢!我对 NoSQL 查询完全陌生,在这里我肯定学到了很多东西。
    猜你喜欢
    • 1970-01-01
    • 2020-03-22
    • 2019-04-17
    • 2013-11-10
    • 2012-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    相关资源
    最近更新 更多