如何使用 MongoDB 聚合获取按日期分组的总和字段值?

How to get the sum field value grouped by date using MongoDB aggregations?

我正在开发收费应用程序,并希望根据每天在 watch 收费广场收取的费用生成报告。

我目前的做法是我有一个包含 dateString 字段的集合,该字段将所有广场的唯一日期和名称作为字段保存,我使用此代码:

const takeLast = str => str.split(/\W/gi).pop().toLowerCase()

const receipt async () => {
    let doc = await Receipt.findOne({dateString: dates.localeString(receipt.date)})

    if (!doc) doc = await new Receipt({
        dateString: dates.localeString(receipt.date)
    })

    doc.total = doc.total + +receipt.amount
    doc[takeLast(receipt.plaza)] = doc[takeLast(receipt.plaza)] + receipt.amount
    await doc.save()

    return doc
}

因此在收据集合中给出这样的数据:

[
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e00c"),
        "date" : ISODate("2020-06-09T15:56:05.777Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e00d"),
        "date" : ISODate("2020-06-16T13:33:41.387Z"),
        "amount" : 20,
        "plaza" : "Shimabala"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e00e"),
        "date" : ISODate("2020-06-15T14:52:51.420Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e00f"),
        "date" : ISODate("2020-06-15T14:52:13.603Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e010"),
        "date" : ISODate("2020-06-16T16:22:53.823Z"),
        "amount" : 20,
        "plaza" : "Mumbwa"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e011"),
        "date" : ISODate("2020-06-20T16:32:50.950Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e012"),
        "date" : ISODate("2020-06-16T13:34:18.070Z"),
        "amount" : 20,
        "plaza" : "Shimabala"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e013"),
        "date" : ISODate("2020-06-16T16:24:09.577Z"),
        "amount" : 20,
        "plaza" : "Mumbwa"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e014"),
        "date" : ISODate("2020-06-20T16:33:41.687Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e015"),
        "date" : ISODate("2020-06-09T15:55:26.727Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e016"),
        "date" : ISODate("2020-05-31T11:13:14.800Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5eef9ddb09fb776392b7e017"),
        "date" : ISODate("2020-05-31T11:10:59.927Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5ef0448b81b0d201ce583251"),
        "date" : ISODate("2020-06-02T09:57:00.090Z"),
        "amount" : 150,
        "plaza" : "Katuba"
    },
    {
        "_id" : ObjectId("5ef4ae62c746cb18df06ab24"),
        "date" : ISODate("2020-06-25T14:01:16.547Z"),
        "amount" : 20,
        "plaza" : "Katuba"
    },
    {
        "_id" : ObjectId("5ef70897a91690446433c601"),
        "date" : ISODate("2020-06-27T08:49:05.053Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5ef761ace88e61128cda7fc8"),
        "date" : ISODate("2020-06-27T15:11:07.123Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    },
    {
        "_id" : ObjectId("5ef8470cb84410217d72da18"),
        "date" : ISODate("2020-06-28T07:22:03.647Z"),
        "amount" : 20,
        "plaza" : "Chongwe"
    }
]

当我 运行 一个 db.receiptReport.find() 查询时,我希望得到以下结果:

[
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d2"),
        "dateString" : "2020-06-09",
        "total" : 40,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 40,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d3"),
        "dateString" : "2020-06-16",
        "total" : 80,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 40,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 40,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 0,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d4"),
        "dateString" : "2020-06-15",
        "total" : 40,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 40,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d5"),
        "dateString" : "2020-06-20",
        "total" : 40,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 40,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d6"),
        "dateString" : "2020-05-31",
        "total" : 40,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 40,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d7"),
        "dateString" : "2020-06-02",
        "total" : 150,
        "manyumbi" : 0,
        "katuba" : 150,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 0,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d8"),
        "dateString" : "2020-06-25",
        "total" : 20,
        "manyumbi" : 0,
        "katuba" : 20,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 0,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0d9"),
        "dateString" : "2020-06-27",
        "total" : 40,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 40,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0da"),
        "dateString" : "2020-06-28",
        "total" : 20,
        "manyumbi" : 0,
        "katuba" : 0,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 20,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    },
    {
        "_id" : ObjectId("5f45c7501fe3d5059d89b0db"),
        "dateString" : "2020-06-29",
        "total" : 40,
        "manyumbi" : 0,
        "katuba" : 40,
        "shimabala" : 0,
        "kafulafuta" : 0,
        "sata" : 0,
        "mulemba" : 0,
        "munkombwe" : 0,
        "kavindele" : 0,
        "livingstone" : 0,
        "kazungula" : 0,
        "mumbwa" : 0,
        "mpika" : 0,
        "kapiri" : 0,
        "chongwe" : 0,
        "chembe" : 0,
        "kalense" : 0,
        "katenshi" : 0,
        "kakonde" : 0,
        "chilonga" : 0,
        "chakulya" : 0,
        "mpongwe" : 0,
        "ntoposhi" : 0
    }
]

如何使用聚合实现同样的效果?

密码是

db.collection.aggregate([
  {
    $addFields: {
      dateOnly: {
        "date": { "$dateToString": { "format": "%Y-%m-%d",  "date": "$date" } }
      }
    }
  },
  {
    $group: {
      _id: null,
      data: { $push: "$$ROOT" },
      allPlaza: { $addToSet: "$plaza" }
    }
  },
  {
    $unwind: "$data"
  },
  {
    "$replaceRoot": {
      "newRoot": { "$mergeObjects": [ "$data", "$$ROOT" ] }
    }
  },
  {
    $group: {
      _id: { date: "$dateOnly.date", plaza: "$plaza" },
      amount: { $sum: "$amount" },
      allPlaza: { "$first": "$allPlaza" }
    }
  },
  {
    $group: {
      _id: "$_id.date",
      plaza: {
        $push: {
          plaza: "$_id.plaza",
          amount: { $sum: "$amount" }
        }
      },
      allPlaza: { "$first": "$allPlaza" }
    }
  },
  {
    $project: {
      data: {
        $map: {
          input: "$plaza",
          in: {
            k: "$$this.plaza",
            v: "$$this.amount"
          }
        }
      },
      allPlaza: {
        $map: {
          input: "$allPlaza",
          in: {
            k: "$$this",
            v: 0
          }
        }
      }
    }
  },
  {
    $project: {
      data: {
        "$arrayToObject": {
          "$concatArrays": ["$allPlaza",  "$data" ]
        }
      }
    }
  },
  {
    $addFields: {
      sum: {
        $reduce: {
          input: "$data",
          initialValue: 0,
          in: { $add: ["$$this.v", "$$value" ] }
        }
      }
    }
  },
  {
    $project: {
      data: {
        "$arrayToObject": "$data"
      },
      sum: 1
    }
  },
  {
    $addFields: {
      "data.total": "$sum"
    }
  }
])

工作Mongo playground