группировать документы по массиву идентификаторов объектов

#mongodb #aggregation-framework

#mongodb #агрегация-фреймворк

Вопрос:

 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. Преобразовать ObjectId s в строку
  3. Объединить все строки идентификаторов в одну строку и сохранить в определенном поле
  4. Группировать по этому полю

Пожалуйста, обратите внимание, что реальные документы достаточно велики (скажем, содержат какое-то тяжелое поле «данные», refs само по себе может содержать в среднем 0-10 элементов, максимум 50), а отфильтрованный ввод может содержать тысячи документов.

Будет ли это наиболее эффективным способом с точки зрения производительности (CPU RAM)?

Обновить

Извините, что не упомянул о важной детали: существуют другие поля, не входящие в массив, которые должны участвовать в группировке. Например

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

скажем, мне нужно сгруппировать их по color refs material

Ответ №1:

Вы можете использовать один $group с $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" } 
} },
 

Комментарии:

1. Привет @Wernfried Domscheit, извините, в моем примере не хватало важной детали. Не могли бы вы взглянуть на это?