mongodb 许多文档的平均数组

mongodb average arrays across many documents

使用 mongodb,我有一个文档集合,其中每个文档都有一个固定长度的浮点值向量,如下所示:

    items = [
        {"id": "1", "vec": [1, 2, 0]},
        {"id": "2", "vec": [6, 4, 1]},
        {"id": "3", "vec": [3, 2, 2]},
    ]

我想取这些向量的逐行平均值。在此示例中,我希望结果为 return

[ (1 + 6 + 3) / 3, (2 + 4 + 2) / 3, (0 + 1 + 2) / 3 ]

这个答案非常接近我正在寻找的答案,但据我所知它只适用于大小为 2 的向量。mongoDB - average on array values

已提供的答案对于大型数组来说性能不是很好。对于上下文,我使用 ~700 维向量。

这应该有效:https://mongoplayground.net/p/PKXqmmW31nW

[
  {
    $group: {
      _id: null,
      a: {
        $push: {
          $arrayElemAt: ["$vec", 0]
        }
      },
      b: {
        $push: {
          $arrayElemAt: ["$vec", 1]
        }
      },
      c: {
        $push: {
          $arrayElemAt: ["$vec", 2]
        }
      }
    }
  },
  {
    $project: {
      a: {
        $avg: "$a"
      },
      b: {
        $avg: "$b"
      },
      c: {
        $avg: "$c"
      }
    }
  }
]

输出:

[
  {
    "_id": null,
    "a": 3.3333333333333335,
    "b": 2.6666666666666665,
    "c": 1
  }
]

这里有一个没有 $avg 运算符的更有效的方法。我会留下其他答案供参考。 https://mongoplayground.net/p/rVERc8YjKZv

db.collection.aggregate([
  {
    $group: {
      _id: null,
      a: {
        $sum: {
          $arrayElemAt: ["$vec", 0]
        }
      },
      b: {
        $sum: {
          $arrayElemAt: ["$vec", 1]
        }
      },
      c: {
        $sum: {
          $arrayElemAt: ["$vec", 2]
        }
      },
      totalDocuments: {
        $sum: 1
      }
    }
  },
  {
    $project: {
      a: {
        $divide: ["$a", "$totalDocuments"]
      },
      b: {
        $divide: ["$b", "$totalDocuments"]
      },
      c: {
        $divide: ["$c", "$totalDocuments"]
      }
    }
  }
])

您可以使用$unwind将值放入单独的文档中,关键是要保留值的索引。然后你可以通过索引使用 $group 并使用 $avg 运算符计算平均值。

db.collection.aggregate([
  {
    $unwind: {
      path: "$vec",
      includeArrayIndex: "i" // unwind and keep index
    }
  },
  {
    $group: {
      _id: "$i", // group by index
      avg: { $avg: "$vec" }
    }
  }, // at this stage, you already get all the values you need, in separate documents. The following stages will put all the values in an array
  {
    $sort: { _id: 1 }
  },
  {
    $group: {
      _id: null,
      avg: { $push: "$avg" }
    }
  }
])

Mongo Playground