【问题标题】:MongoDB Unwind In Parallel Stages or CombineMongoDB 在并行阶段展开或合并
【发布时间】:2020-02-03 14:39:55
【问题描述】:

给定以下数据:

let tasks = [
  {
    _id: 1,
    task_number: 1,
    description: 'Clean Bathroom',
    customer: 'Walmart',
    users_worked: [
      {user: 'Jonny', hours: 1},
      {user: 'Cindy', hours: 1}
    ],
    supplies_used: [
      {item_code: 'LD4949', description: 'Liquid Detergent', quantity: 1}
    ]
  },
  {
    _id: 2,
    task_number: 2,
    description: 'Stock Cheeses',
    customer: 'Walmart',
    users_worked: [
      {user: 'Mark', hours: 3.0},
      {user: 'Shelby', hours: 2.0}
    ],
    supplies_used: []
  }
];

假设我想以列表格式显示一个表格:

task_number | description | customer | users | users_worked.hours (sum) | supplies_used.quantity (sum)
----------------------------------------------------------------------------------------------
      1 | 'Clean Bathroom' | 'Walmart' | 'Jonny, Cindy' |        2                |           1
      2 | 'Stock Cheeses'  | 'Walmart' | 'Mark, Shelby' |        5                |           0

聚合:

[
  {
    "unwind: {
      "path": "$users_worked",
      "preserveNullAndEmptyArrays": true
    }
  },
  {
    "unwind: {
      "path": "$supplies_used",
      "preserveNullAndEmptyArrays": true
    }
  },
  {
    $group: {
      _id: "$_id",
      task_number: {
        $first: "$task_number"
      },
      description: {
        $first: "$description"
      },
      customer: {
        $first: "$customer"
      },
      users: {
        $push: "$users_worked.user"
      },
      users_worked: {
        $sum: "$users_worked.hours"
      },
      supplies_used: {
        $sum: "$supplies_used.quantity"
      }
  }
]

问题是我需要$unwind 两个数组(users_workedsupplies_used),这最终会扭曲我的结果(笛卡尔积)。由于任务 #1 在 users_worked 数组中有 2 个元素,它会使我的 supplies_used 计数变为 2。

这是一个简单的例子,可能有很多数组,每个元素越多,数据的倾斜度就越大。

有没有一种聚合方法可以分别展开多个数组,这样它们就不会相互倾斜?我看过一个创建 1 个组合对象的示例,其中只有 1 个展开源。似乎不明白如何做我想做的事。

* 编辑 *

我看到您可以使用$zip mongo aggregate 命令将多个数组组合成一个数组。这是一个好的开始:

arrays: {
  $map: {
    input: {
      $zip: {
        inputs: [
          '$users_worked',
          '$supplies_used'
        ], 
      }
    },
    as: 'zipped',
    in: {
      users_worked: {
        $arrayElemAt: [
          '$$zipped',
          0
        ]
      },
      supplies_used: {
        $arrayElemAt: [
          '$$zipped',
          1
        ]
      }

如果我有一个数组数组,我该如何使用这个$zip 命令。例如:

let tasks = [
  {
    _id: 1,
    task_number: 1,
    description: 'Clean Bathroom',
    customer: 'Walmart',
    users_worked: [
      {user: 'Jonny', hours: 1},
      {user: 'Cindy', hours: 1}
    ],
    supplies_used: [
      {item_code: 'LD4949', description: 'Liquid Detergent', quantity: 1}
    ],
    invoices: [
      {
        invoicable: true,
        items: [
           {item_code: 'LD4949', price: 39.99, quantity: 1, total: 39.99},
           {item_code: 'Hours', price: 50.00, quantity: 2, total: 100.00}
        ]
      }
    ]
  },
  {
    _id: 2,
    task_number: 2,
    description: 'Stock Cheeses',
    customer: 'Walmart',
    users_worked: [
      {user: 'Mark', hours: 3.0},
      {user: 'Shelby', hours: 2.0}
    ],
    supplies_used: [],
    invoices: []
  }
];

我想在我的列表中包含 invoices.items.total 的总和。

【问题讨论】:

    标签: mongodb aggregation-framework aggregation


    【解决方案1】:

    您可以使用$reduce 来聚合名称并使用$sum 来汇总数字,而不是使用$unwind$group

    db.collection.aggregate([
        {
            $project: {
                task_number: 1,
                description: 1,
                customer: 1,
                users: {
                    $reduce: {
                        input: "$users_worked",
                        initialValue: "",
                        in: {
                            $concat: [ "$$value", ", ", "$$this.user" ]
                        }
                    }
                },
                users_worked: { $sum: "$users_worked.hours" },
                quantity: { $sum: "$supplies_used.quantity" }
            }
        }
    ])
    

    Mongo Playground

    【讨论】:

      【解决方案2】:

      我能够使用多层 $zip 来解决这个问题。从根层开始,根上的所有数组都需要压缩然后展开。然后找到该层上任何字段的 $sum,然后找到下一层,$zip 新数组,然后展开,然后对该层求和,等等。

      问题是您不想展开多个数组或得到笛卡尔积。需要合并成 1 个数组然后展开然后一切都正确!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-23
        • 2012-11-06
        • 2018-06-13
        • 1970-01-01
        • 2015-08-31
        • 2018-03-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多