Агрегат MongoDB для извлечения значений из вложенного массива и возврата общего количества

#javascript #mongodb #mongodb-nodejs-driver

#javascript #mongodb #mongodb-nodejs-driver

Вопрос:

У меня есть такая структура коллекции:

 [
   "_id": "61a013b59f9dd0ebfd23ftgb",
   "modules": [
     {
       "_id": "61a013b59f9dd0ebfd964dgh",
       "videos": [
         {
           "_id": "213412",
           "progress": 100
         },
         {
           "_id": "61a013b59f9dd0ebfd965f4a",
           "progress": 0
         },
       ]
     },
     {
       "_id": "43556hujferwdhgsdft",
       "videos": [
         {
           "_id": "fdsg3sg98er989890",
           "progress": 66
         },
         {
           "_id": "fdsg3sg98er989890",
           "progress": 100
         },
         {
           "_id": "fdsg3sg98er989890",
           "progress": 100
         }
       ]
     }
   ]
 ]
 

Я пытаюсь вернуть общий прогресс для каждого «модуля», суммируя все видео, прогресс которых равен 100, и создавая процент, основанный на количестве видео в модуле. Например, первый модуль должен возвращать «module_progess» из 50 внутри него, поскольку это завершило 1/2 видео.

 {
   "_id": "61a013b59f9dd0ebfd964dgh",
   "module_progress": 50,
   "videos": [
     {
       "_id": "213412",
       "progress": 100
     },
     {
       "_id": "61a013b59f9dd0ebfd965f4a",
       "progress": 0
     },
   ]
},
 

Как мне получить доступ к каждому объекту videos, чтобы выполнить это вычисление и добавить новое поле в ответ?

Ответ №1:

Запрос 1

  • сопоставление по модулям
  • и добавьте поле для каждого со средним прогрессом видео

Тестовый код здесь

 aggregate(
[{"$set": 
   {"modules": 
     {"$map": 
       {"input": "$modules",
        "in": 
        {"$mergeObjects": 
          ["$this",
           {"module_progress": 
             {"$avg": 
               {"$map": 
                 {"input": "$this.videos.progress",
                  "in": 
                  {"$cond": [{"$eq": ["$progress", 100]}, "$progress", 0]},
                  "as": "progress"}}}}]}}}}}])
 

Запрос 2

  • размотать
  • замените root, чтобы улучшить структуру
  • добавьте поле avg

Тестовый код здесь

 aggregate(
[{"$unwind": {"path": "$modules"}},
  {"$replaceRoot": {"newRoot": "$modules"}},
  {"$set": 
    {"module_progress": 
      {"$avg": 
        {"$map": 
          {"input": "$videos.progress",
            "in": {"$cond": [{"$eq": ["$this", 100]}, "$this", 0]}}}}}}])
 

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

1. это потрясающе — и близко. Однако вместо среднего значения, если видео не завершено на 100%, его необходимо классифицировать как 0. Так, например, второй модуль будет завершен на 2/3, то есть на 66,6%. Как бы я это сделал?

2. я обновил его, добавив одну дополнительную карту перед средним значением, вы также можете выполнить уменьшение и суммирование, но это тоже работает, просто запрос стал немного больше

3. Удивительные. Многому научился из этого. Спасибо.