展开元素后对多维数组进行分组



再次使用mongoDB。我真的很喜欢聚合,但仍然无法"获得它"。

这是我的数组:

{
    "_id" : ObjectId("55951b2bf41edfc80b00002a"),
    "orders" : [ 
    {
        "id" : "55929142f41edfdc0f00002f",
        "name" : "XYZ",
        "id_basket" : 1,
        "card" : [ 
            {
                "id" : "250",
                "serial" : "B",
                "type" : "9cf4161002b9eda349bb9c5ae64b9f4a",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    }
                ]
            },
            {
                "id" : "250",
                "serial" : "B",
                "type" : "9cf4161002b9eda349bb9c5ae64b9f4a",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    }
                ]
            }
        ],
        "full_amount" : "40",
    },
    {
        "id" : "55929142f41edfdc0f00002f",
        "name" : "XYZ",
        "id_basket" : 1,
        "card" : [ 
            {
                "id" : "250",
                "serial" : "B",
                "type" : "9cf4161002b9eda349bb9c5ae64b9f4a",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    }
                ]
            },
            {
                "id" : "250",
                "serial" : "B",
                "type" : "9cf4161002b9eda349bb9c5ae64b9f4a",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : {
                            "name" : "Normal",
                            "price" : "10",
                            "price_disp" : "10 €",
                        }
                    }
                ]
            }
        ],
        "full_amount" : "40",
    },
],
"rate" : "0.23",
"date" : "2015-07-02 13:04:34",
"id_user" : 97,
}

我想输出这样的东西:

{
    "_id" : ObjectId("55951b2bf41edfc80b00002a"),
    "orders" : [ 
    {
        "id" : "55929142f41edfdc0f00002f",
        "name" : "XYZ",
        "card" : [ 
            {
                "id" : "250",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            },
            {
                "id" : "250",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            }
        ],
        "full_amount" : "40",
    },
    {
        "id" : "55929142f41edfdc0f00002f",
        "name" : "XYZ",
        "card" : [ 
            {
                "id" : "250",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            },
            {
                "id" : "250",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000030",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            }
        ],
        "full_amount" : "40",
    },
],
"rate" : "0.23",
"date" : "2015-07-02 13:04:34",
}

我尝试了许多展开、投影和分组的组合,但都没能得到我想要的。有人能帮我吗?

您可能不应该将聚合框架用于这样的任务,因为这些任务实际上不会在文档之间"聚合"任何内容。这实际上是一项"投影"任务,因为您所要求的只是"更改"文档的结构,而这项任务可能更适合在检索文档后在客户端中进行编码。

一个很好的原因是,像$unwind这样的操作在性能方面成本非常高。$unwind所做的是为出现的每个数组成员生成文档内容的"副本",这将导致需要处理更多的文档。

把它想象成一个具有"一对多"关系的"SQL联接",唯一的区别是数据本身包含在一个文档中。处理$unwind模拟"联接"结果,即为每个"子"(多)文档复制"主"(一个)文档内容。

为了应对人们进行的此类操作,MongoDB 2.6引入了$map运算符,该运算符处理文档中的数组元素。

因此,您不需要执行多个(或任何)$unwind操作,而是可以在$project阶段中使用$map来处理文档本身中的数组:

db.collection.aggregate([
  { "$project": {
    "orders": { "$map": {
      "input": "$orders",
      "as": "o",
      "in": {
        "id": "$$o.id",
        "name": "$$o.name",
        "card": { "$map": {
          "input": "$$o.card",
          "as": "c",
          "in": {
            "id": "$$c.id",
            "serial": "$$c.serial",
            "name": "$$c.name",
            "ticket": { "$map": {
              "input": "$$c.ticket",
              "as": "t",
              "in": {
                "id": "$$t.id",
                "name": "$$t.name",
                "price": "$$t.price.price_disp"
              }
            }}
          }
        }},
        "full_amount": "$$o.full_amount"
      }    
    }},
    "rate": 1,
    "date": 1
  }}
])

操作相当简单,因为每个"数组"都有自己的变量名,对于这样的简单投影操作,真正剩下的就是选择您想要的字段。

在早期版本中,使用$unwind进行处理要困难得多:

db.collection.aggregate([
  { "$unwind": "$orders" },
  { "$unwind": "$orders.card" },
  { "$unwind": "$orders.card.ticket" },
  { "$group": {
    "_id": { 
      "_id": "$_id",
      "orders": {
        "id": "$orders.id",
        "name": "$orders.name",
        "card": {
          "id": "$orders.card.id",
          "serial": "$orders.card.serial",
          "name": "$orders.card.name"
        },
        "full_amount": "$orders.full_amount"
      },
      "rate": "$rate",
      "date": "$date"
    },
    "ticket": { 
      "$push": {
        "id": "$orders.card.ticket.id",
        "name": "$orders.card.ticket.name",
        "price": "$orders.card.ticket.price.price_disp"
      }
    }
  }},
  { "$group": {
    "_id": { 
      "_id": "$_id._id",
      "orders": {
        "id": "$_id.orders.id",
        "name": "$_id.orders.name",
        "full_amount": "$_id.orders.full_amount"
      },
      "rate": "$_id.rate",
      "date": "$_id.date"
    },
    "card": { 
      "$push": {
        "id": "$_id.orders.card.id",
        "serial": "$_id.orders.card.serial",
        "name": "$_id.orders.card.name",
        "ticket": "$ticket"
      }
    }
  }},
  { "$group": {
    "_id": "$_id._id",
    "orders": { 
      "$push": {
        "id": "$_id.orders.id",
        "name": "$_id.orders.name",
        "card": "$card",
        "full_amount": "$_id.orders.full_amount"
      }
    },
    "rate": { "$first": "$_id.rate" },
    "date": { "$first": "$_id.date" }
  }}
])

因此,仔细阅读,您应该看到,由于您$unwind三次,因此也有必要$group"三次",同时仔细分组每个"级别"的所有不同值,并通过$push重新构建数组。

这真的不建议如前所述:

  • "不是分组/聚合任何东西",并且每个子文档"必须"包含的"唯一"itentifier,因为重新构造数组需要"分组"操作。(请参阅:注意

  • 此处的$unwind操作成本非常高。所有文档信息都是由"n"数组X"n"个数组元素等因子重新生成的。因此,聚合管道中的数据比集合或查询选择本身实际包含的数据多得多。

因此,总之,对于"重新格式化数据"的一般处理,您应该处理代码中的每个文档,而不是将其"扔"到聚合管道中。

如果您的文档数据需要"足够"的操作,这会对返回的结果大小产生"实质性的差异",并且您认为这比提取整个文档并在客户端中进行操作更有效,那么您应该使用$project表单,如$map操作所示。


边栏

你原来的"标签"在这里提到了"PHP"。

包括聚合在内的所有MongoDB查询都没有特定的语言,只是"数据结构",对于这些语言(PHP、JavaScript、python等),它们大多以"原生形式"表示,对于那些没有"原生"自由结构表达格式的语言(C、C#、Java),它们使用"构建器方法"表示。

在所有情况下,都有可用于JSON的简单解析器,这在这里是一个常见的"linqua-franca",因为MongoBShell本身是基于JavaScript的,并在本地理解JSON结构(作为实际的JavaScript对象)。

因此,在处理此类示例时,请使用以下工具:

  • json_decode:深入了解如何构建本机数据结构。

  • json_encode:以便根据任何json表示的样本检查您的本地数据结构。

这里的所有内容都只是简单的"键/值"array()表示法,尽管是嵌套的。但了解这些工具并定期使用它们可能是一种很好的做法。


注意:

您提供的数据示例看起来非常像您为了创建多个项目而"剪切并粘贴"数据,因为各种"子项目"都共享相同的"id"值。

您的"真实"数据不应该这样做!所以我希望它不会,但如果是这样,那么就修复它

为了使第二个示例可行(第一个示例非常好),需要将数据更改为包含每个子元素的"唯一"id"值。

正如我在这里使用的:

{
    "_id" : ObjectId("55951b2bf41edfc80b00002a"),
    "orders" : [ 
    {
        "id" : "55929142f41edfdc0f00002a",
        "name" : "XYZ",
        "card" : [ 
            {
                "id" : "250",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000031",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000032",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            },
            {
                "id" : "251",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000033",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000034",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            }
        ],
        "full_amount" : "40",
    },
    {
        "id" : "55929142f41edfdc0f00002b",
        "name" : "XYZ",
        "card" : [ 
            {
                "id" : "252",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000035",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000036",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            },
            {
                "id" : "253",
                "serial" : "B",
                "name" : "Eco",
                "ticket" : [ 
                    {
                        "id" : "55927d41f41edfd00f000037",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    },
                    {
                        "id" : "55927d41f41edfd00f000038",
                        "name" : "ZZZ",
                        "price" : "10 €"
                    }
                ]
            }
        ],
        "full_amount" : "40",
    }
    ],
    "rate" : "0.23",
    "date" : "2015-07-02 13:04:34",
}

相关内容

  • 没有找到相关文章

最新更新