首页 > 解决方案 > 按 ObjectId 数组对文档进行分组

问题描述

db.test.insert([
  { name: 'one', refs: [ObjectId('111'), ObjectId('222'), ObjectId('333')] },
  { name: 'two', refs: [ObjectId('222'), ObjectId('333')] },
  { name: 'three', refs: [ObjectId('222'), ObjectId('333'), ObjectId('111')] },
])

理想情况下,如果文档具有所有相同的引用(以及相同数量的引用),我不想对它们进行分组,不管它们在数组字段中的顺序是什么。像这样

[
  {
    names: ['one', 'three'],
  },
  {
    names: ['two'],
  }
]

据我了解,我需要:

  1. refs对元素进行排序
  2. ObjectIds 转换为字符串
  3. 将所有 id 字符串连接到单个字符串并保存到特定字段
  4. 按该字段分组

请注意,真实文档足够大(例如,包含一些繁重的“数据”字段,refs本身平均可以包含 0-10 个项目,最多 50 个),过滤后的输入可以包含数千个文档。

就生产力(CPU + RAM)而言,这会是最有效的方式吗?

更新

很抱歉没有提到一个重要的细节:还有其他非数组字段应该参与分组。例如

{
  name: 'can',
  color: 'green',
  refs: [ObjectId(1), ObjectId(2)],
  material: 'plastic',
  price: 50,
}

说我需要按color+ refs+对它们进行分组material

标签: mongodbaggregation-framework

解决方案


您可以使用单个$groupwith $setUnion

db.test.aggregate([
   { $group: { _id: { $setUnion: "$refs" }, names: { $push: "$name" } } },
   { $unset: "_id" }
])

如果您有更多要分组的字段,只需将它们添加到_id

{ $group: { 
   _id: { 
      refs: { $setUnion: "$refs" }, 
      color: "$color", 
      material: "$material" 
   }, 
   names: { $push: "$name" } 
} },

推荐阅读