【问题标题】:Aggregation in MongoDB with Array of objectsMongoDB中的聚合与对象数组
【发布时间】:2020-07-02 04:56:31
【问题描述】:

我有以下 mongoDB 文档 -

{
    "_id" : ObjectId("5e71a1f3081c4b70cdbc438f"),
    "DataSetID" : ObjectId("5e71a1f3081c4b70cdbc438e"),
    "row" : [ 
        {
            "key" : "Region",
            "prev" : "root",
            "value" : "Australia and Oceania",
            "typeOfValue" : "string",
            "currentDepth" : 1
        }, 
        {
            "key" : "Country",
            "prev" : "root",
            "value" : "Tuvalu",
            "typeOfValue" : "string",
            "currentDepth" : 1
        }, 
        {
            "key" : "Item Type",
            "prev" : "root",
            "value" : "Baby Food",
            "typeOfValue" : "string",
            "currentDepth" : 1
        }, 
        {
            "key" : "Sales Channel",
            "prev" : "root",
            "value" : "Offline",
            "typeOfValue" : "string",
            "currentDepth" : 1
        }, 
        {
            "key" : "Order Priority",
            "prev" : "root",
            "value" : "H",
            "typeOfValue" : "string",
            "currentDepth" : 1
        }, 
        {
            "key" : "Order Date",
            "prev" : "root",
            "value" : ISODate("2010-05-27T18:30:00.000Z"),
            "typeOfValue" : "date",
            "currentDepth" : 1
        }, 
        {
            "key" : "Order ID",
            "prev" : "root",
            "value" : 669165933,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }, 
        {
            "key" : "Ship Date",
            "prev" : "root",
            "value" : ISODate("2010-06-26T18:30:00.000Z"),
            "typeOfValue" : "date",
            "currentDepth" : 1
        }, 
        {
            "key" : "Units Sold",
            "prev" : "root",
            "value" : 9925,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }, 
        {
            "key" : "Unit Price",
            "prev" : "root",
            "value" : 255.28,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }, 
        {
            "key" : "Unit Cost",
            "prev" : "root",
            "value" : 159.42,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }, 
        {
            "key" : "Total Revenue",
            "prev" : "root",
            "value" : 2533654,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }, 
        {
            "key" : "Total Cost",
            "prev" : "root",
            "value" : 1582243.5,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }, 
        {
            "key" : "Total Profit",
            "prev" : "root",
            "value" : 951410.5,
            "typeOfValue" : "number",
            "currentDepth" : 1
        }
    ]
}

假设我们有 100 份这样的文件。 我想进行一个聚合查询,按让我们说 key == 'Country' 的值进行分组,即 Tuvalu 、 India 等,并给我每个国家的 key == 'Total Profit' 的值的总和。

换句话说,给我 values 的总和,其中 key == 'Total Profit' 同时对 key = 的 values 进行分组= '国家'.

可以更改数据结构,因为我输入的是非结构化 JSON 数据,而且我事先不知道键,这就是我想出 json 数组的原因。

最终结果我想要这样的东西:

[
{ 
_id : 'Tuvalu',
value : 100
},
{
_id : 'India',
value : 160
}
]

我们怎样才能做到这一点?

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    试试下面的查询,它有更好优化的可选阶段,你可以根据需要/选择排除:

    db.collection.aggregate([
      /** Optional match stage but can reduce data set size for further stages
       * (Get docs where rows array has an object with a key field & value 'Country') */
      { $match: { "row.key": "Country" } },
      /** Using project to retain only needed fields which reduce size of doc,
       * Convert row array into row object {country : ..., totalProfit : ... } */
      {
        $project: {
          _id: 0,
          row: {
            /** Iterate on row's, So '$$this' is each object & '$$value' is values in initialValue */
            $reduce: {
              input: "$row",
              initialValue: {
                country: "",
                totalProfit: 0
              },
              in: {
                country: {
                 /** If current object key is Country then push value from current object to 'country' in initialValue
                  * otherwise return existing 'country' value to 'country' every time */
                  $cond: [
                    { $eq: ["$$this.key", "Country"] }, 
                    "$$this.value",
                    "$$value.country"
                  ]
                },
                totalProfit: {
                  $cond: [
                    { $eq: ["$$this.key", "Total Profit"] },
                    "$$this.value",
                    "$$value.totalProfit"
                  ]
                }
              }
            }
          }
        }
      },
      /** group on country field & sumup values of totalProfit */
      {
        $group: { _id: "$row.country", value: { $sum: "$row.totalProfit" } }
      }
    ]);
    

    测试: MongoDB-Playground

    【讨论】:

    • 它有效。谢谢兄弟,不知什么时候开始,我一直在绞尽脑汁。另外,您如何看待数据结构?除了这个,你还有什么建议吗?
    • @SiddhantShah :不幸的是,在完全了解您的应用程序和数据事务的情况下,我无法对您的数据结构提出太多建议,但请检查:docs.mongodb.com/manual/core/data-modeling-introduction,快速阅读它肯定可以帮助您这..
    • 简而言之,我必须存储任何类型的 JSON 数据,这些数据可以“n”级嵌套在一个易于查询的表单中,并且我可以对其运行聚合查询。我不会事先知道 JSON 对象的键,所以我需要一种统一的方式来存储数据。
    • @SiddhantShah :我必须这样做,然后您的选择就是您现在正在做的事情将其放入一个数组中,但请记住,尽量使您的数组大小尽可能小导致查询数组字段或在数组上创建索引可能就像将一个文档分解为多个文档:-)
    • 数组大小将等于编号。字段。如果用户发送大量 JSON 数据,我不知道如何限制它。此外,我在 dataSetID 上有一个索引,所有查询将首先使用 dataSetID 获取内存中的所有匹配文档,然后提前查询。
    猜你喜欢
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 2017-07-14
    • 2020-07-27
    相关资源
    最近更新 更多