MongoDB заполняет отсутствующие даты в конвейере агрегации

У меня есть этот трубопровод:

    let pipeline = [
      {
        $match: {
          date: { $gte: new Date("2022-10-19"), $lte: new Date("2022-10-26") },
        },
      },

      {
        $group: {
          _id: "$date",
          tasks: { $push: "$$ROOT" },
        },
      },
      {
        $sort: { _id: -1 },
      },
    ];

    const aggregationData = await ScheduleTaskModel.aggregate(pipeline);

где я группирую все «задачи» между диапазоном дат по дате и получаю этот результат:

[
    {
        "date": "2022-10-21T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "date": "2022-10-20T00:00:00.000Z",
        "tasks": [...tasks with this date]
    }
]

как вы видите, у меня есть «задачи» только для 2 дат в этом диапазоне, что, если я хочу, чтобы все даты отображались, даже те, у которых нет задач, поэтому это было бы так с пустыми массивами?

[
    {
        "date": "2022-10-26T00:00:00.000Z",
        "tasks": []
    },
    {
        "date": "2022-10-25T00:00:00.000Z",
        "tasks": []
    },
    {
        "date": "2022-10-24T00:00:00.000Z",
        "tasks": []
    },
    {
        "date": "2022-10-23T00:00:00.000Z",
        "tasks": []
    },
    {
        "date": "2022-10-22T00:00:00.000Z",
        "tasks": []
    },
    {
        "date": "2022-10-21T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "date": "2022-10-20T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "date": "2022-10-19T00:00:00.000Z",
        "tasks": []
    },
]

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

Возможно, вам просто нужно немного подождать, пока Атлас будет обновлен.

Wernfried Domscheit 22.10.2022 22:56
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Новая функция $densify будет, конечно, самой простой. Ручной способ сделать это будет следующим:

db.collection.aggregate([
  {
    $group: {
      _id: null,
      data: { $push: "$$ROOT" }
    }
  },
  {
    $set: {
      dates: {
        $map: {
          input: { $range: [ 0, 8 ] }, // maybe more dynamic with $dateDiff -> { $dateDiff: { startDate: new Date("2022-10-19"), endDate: new Date("2022-10-26") }, unit: "day" } }
          in: {
            date: {
              $dateAdd: {
                startDate: ISODate("2022-10-19T00:00:00.000Z"),
                unit: "day",
                amount: "$$this"
              }
            }
          }
        }
      }
    }
  },
  {
    $set: {
      dates: {
        $map: {
          input: "$dates",
          as: "d",
          in: {
            $mergeObjects: [
              "$$d",
              {
                tasks: {
                  $filter: {
                    input: "$data",
                    cond: { $eq: [ "$$d.date", "$$this.date" ] }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      data: {
        $map: {
          input: "$dates",
          in: {
            $cond: {
              if: { $eq: [ "$$this.tasks", [] ] },
              then: "$$this",
              else: { $first: "$$this.tasks" }
            }
          }
        }
      }
    }
  },
  { $unwind: "$data" },
  { $replaceWith: "$data" }
])

Детская площадка Монго

Ответ принят как подходящий

Ответ @WernfriedDomscheitAnother имеет обратную сторону: группировка всех документов в коллекции, создание одного большого документа, в то время как документ имеет ограничение по размеру. Вариацией на него, без этого недостатка, может быть:

  1. $match только соответствующий документ, такой же, как в вашем текущем запросе
  2. Используйте $facet, чтобы обработать случай отсутствия соответствующих документов. Это позволит вам сгруппировать все соответствующие документы, как вы сделали это в своем запросе, но сохранить рабочий документ, даже если он есть.
  3. Добавьте соответствующие даты в массив (поскольку мы используем $facet, это произойдет, даже если первое совпадение пусто)
  4. Объедините массив совпадающих данных с массивом пустых записей, сначала используйте реальные данные.
  5. $unwind разделите документы по дате и $group еще раз по дате, чтобы удалить дубликаты.
  6. Отформатируйте результат
db.collection.aggregate([
  {$match: {date: {$gte: new Date("2022-10-19"), $lte: new Date("2022-10-26")}}},
  {$facet: {
      data: [
        {$group: {_id: "$date", tasks: {$push: "$$ROOT"}}},
        {$project: {date: "$_id", tasks: 1}}
      ]
  }},
  {$addFields: {
      dates: {$map: {
          input: {$range: [0, 8]},
          // maybe more dynamic with $dateDiff -> { $dateDiff: { startDate: new Date("2022-10-19"), endDate: new Date("2022-10-26") }, unit: "day" } }
          in: {
            date: {$dateAdd: {
                startDate: ISODate("2022-10-19T00:00:00.000Z"),
                unit: "day",
                amount: "$$this"
            }},
            tasks: []
          }
      }}
  }},
  {$project: {data: {$concatArrays: ["$data", "$dates"]}}},
  {$unwind: "$data"},
  {$group: {_id: "$data.date", "tasks": {$first: "$data.tasks"}}},
  {$project: { _id: 0, date: "$_id", tasks: 1 }},
  {$sort: { date: -1 }},
])

Посмотрите, как это работает на примере детской площадки

Я не могу понять эту часть --> input: {$range: [0, 8]},

Vaggelis 23.10.2022 10:10

Это создаст цикл с 8 итерациями. Для каждой итерации будет добавлено количество дней в качестве индекса итерации к дате начала.

nimrod serok 23.10.2022 10:13

Другие вопросы по теме