首页 > 解决方案 > 计算数组子元素中持续时间的“AVG”

问题描述

我正在研究一个伪工作流程,我想收集有关全局和详细平均持续时间的统计数据。

这是我的示例数据:

[
  {
    "_id": "20200624-093335 362-362956200",
    "workers": [
      {
        "order": 0,
        "startAt": ISODate("2020-06-24T09:39:00.033+02:00"),
        "endAt": ISODate("2020-06-24T09:39:00.036+02:00")
      },
      {
        "order": 1,
        "startAt": ISODate("2020-06-24T09:39:15.096+02:00"),
        "endAt": ISODate("2020-06-24T09:39:35.025+02:00")
      },
      {
        "order": 2,
        "startAt": ISODate("2020-06-24T09:39:59.911+02:00"),
        "endAt": ISODate("2020-06-24T09:46:15.026+02:00")
      }
    ],
    "startAt": ISODate("2020-06-24T09:39:00.029+02:00"),
    "endAt": ISODate("2020-06-24T09:47:05.032+02:00")
  },
  /** 3*/
  {
    "_id": "20200624-093017 360-360067800",
    "workers": [
      {
        "order": 0,
        "startAt": ISODate("2020-06-24T09:30:20.093+02:00"),
        "endAt": ISODate("2020-06-24T09:30:20.096+02:00")
      },
      {
        "order": 1,
        "startAt": ISODate("2020-06-24T09:30:30.106+02:00"),
        "endAt": ISODate("2020-06-24T09:30:50.019+02:00")
      },
      {
        "order": 2,
        "startAt": ISODate("2020-06-24T09:31:45.258+02:00"),
        "endAt": ISODate("2020-06-24T09:38:00.021+02:00")
      }
    ],
    "startAt": ISODate("2020-06-24T09:30:20.027+02:00"),
    "endAt": ISODate("2020-06-24T09:38:50.023+02:00")
  }
]

预期结果是:

{
  _id: "stats",
  avg: 497499.5,
  workers: [
    {
      order: 0,
      avg: 3
    },
    {
      order: 1,
      avg: 19921
    },
    {
      order: 2,
      avg: 374939
    }
  ]
}

我当前的管道是这样定义的:

db.collection.aggregate([
  {
    $addFields: {
      workers: {
        $map: {
          input: "$workers",
          as: "i",
          "in": {
            $arrayToObject: {
              $concatArrays: [
                {
                  $objectToArray: "$$i"
                },
                [
                  {
                    k: "duration",
                    v: {
                      $subtract: [
                        "$$i.endAt",
                        "$$i.startAt"
                      ]
                    }
                  }
                ]
              ]
            }
          }
        }
      },
      duration: {
        $subtract: [
          "$endAt",
          "$startAt"
        ]
      }
    }
  }
])

此管道计算来自对象和子元素的所有持续时间。

计算全局平均值没有问题,但我不知道如何计算子元素平均值!

这是我的游乐场 => https://mongoplayground.net/p/Ob5ck6Pue9Y

标签: mongodbaggregation-framework

解决方案


聚合给出与预期相同的结果和值。请注意,order无法在结果中确定字段的排序顺序。

db.collection.aggregate([ 
  { 
      $unwind: "$workers" 
  },
  { 
      $group: {
           _id: "$workers.order", 
           order_avg: { $avg: { $subtract: [ "$workers.endAt", "$workers.startAt" ] } },
           global_values: { $addToSet: { gid: "$_id",  duration: { $subtract: [ "$endAt", "$startAt" ] } } }
      } 
  },
  { 
      $unwind: "$global_values" 
  },
  { 
      $group: {
          _id: { order: "$_id", order_avg: "$order_avg" },
          global_avg: { $avg: "$global_values.duration" }
      } 
  },
  { 
      $group: { 
          _id: "stats",
          avg: { $first: "$global_avg" }, 
          workers: { $push: "$_id" }, 
      } 
  },
] ).pretty()

推荐阅读