Как преобразовать массив объектов во вложенный объект в конвейере агрегации MongoDB

#mongodb #aggregation-framework

Вопрос:

В настоящее время я занимаюсь проектом, в котором моя система управления базами данных-MongoDB. Я пишу конвейер агрегации, в котором есть несколько этапов. В настоящее время я борюсь на определенном этапе, когда я хочу получить следующий результат. В MongoDB так много выражений операторов, что я не знаю, какое из них использовать для достижения этой цели. У меня есть коллекция под названием Стили и артикулы, которые выглядят следующим образом:

 // Schema for styles
const styles = mongoose.Schema({
  id: Number,
  productId: Number,
  name: String,
  sale_price: String,
  original_price: String,
  default_price: Boolean,
}, {
  strict: false,
});

// Schema for skus
const skus = mongoose.Schema({
  id: Number,
  styleId: Number,
  size: String,
  quantity: String,
}, {
  strict: false,
});
 

Каждый стиль может иметь несколько артикулов, отношения «один ко многим». В моем конвейере агрегирования я использую $lookup для поиска всех артикулов этого конкретного стиля и добавления нового поля под названием артикулы в документе стили. Я получаю такие результаты после поиска$.

 {
            "style_id": 1,
            "name": "Forest Green amp; Black",
            "original_price": "140",
            "sale_price": "0",
            "default?": true,
             "skus": [
                { 
                   "id": 37,
                   "styleId": 1,
                   "size": "XS",
                   "quantity": 16 
                },
                { 
                   "id": 38,
                   "styleId": 1,
                   "size": "S",
                   "quantity": 8
                } 
              ]  

}
 

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

 {
            "style_id": 1,
            "name": "Forest Green amp; Black",
            "original_price": "140",
            "sale_price": "0",
            "default?": true,
             "skus": {
                  "37": {
                    "styleId": 1,
                   "size": "XS",
                   "quantity": 16 
                  },
                  "38": {
                   "styleId": 1,
                   "size": "S",
                   "quantity": 8
                  }
               }
                    

}
 

Может ли кто-нибудь дать какое-либо представление о том, как структурировать данные, как описано выше, в конвейере агрегации? Любая помощь будет очень признательна. Заранее спасибо.

Ответ №1:

Вы можете использовать $map или $reduce преобразовать объекты в массиве в форму

 [
 {
  k: <key1>
  v: <value1>
 },
 {
  k: <key2>
  v: <value2>
 }
]
 

Затем используйте $arrayToObject , который преобразует массив в объект, подобный:

 { 
    <key1>: <value1>,
    <key2>: <value2> 
}
 

Вместе это может выглядеть так:

 {$addFields: {
    skus: {
      $arrayToObject: {
        $map: {
          input: "$skus",
          in: {
            k: {$toString: "$this.id"},
            v: "$this"
          }
        }
      }
    }
}}
 

Игровая площадка

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

1. Джо, большое тебе спасибо за ответ. Я попробовал ваше решение, но возникли трудности с тем, как его реализовать $reduce здесь. { $reduce: { input: skus, initialValue: , in: }} .. Если у вас есть немного времени, не могли бы вы объяснить немного больше об этом? Но в любом случае, еще раз спасибо.