es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Censo de Agregación de MongoDB

Me gustaría agregar estos datos, necesito contar los objetos por mes, como un censo. Para cada artículo tengo una fecha de llegada y una fecha de salida, este artículo tiene la suma +1 en los meses dentro de este rango. ¿Cómo puedo hacer esto?

DATOS:

[{
    _id:1
    history:
    [
       {_id:1, date:2021-03-01, type:"Departure"},
       {_id:2, date:2021-01-01, type:"Arrival"}
    ]
},
{
    _id:2
    history:
    [
       {_id:1, date:2021-07-03, type:"Departure"},
       {_id:2, date:2021-02-10, type:"Arrival"}
    ]
},
{
    _id:3
    history:
    [
       {_id:1, date:2021-08-22, type:"Departure"},
       {_id:2, date:2021-11-5, type:"Arrival"}
    ]
}]

RESULTADO:

[
    {month:1, year:2021, counter:1},
    {month:2, year:2021, counter:2},
    {month:3, year:2021, counter:2},
    {month:3, year:2021, counter:1},
    {month:4, year:2021, counter:1},
    {month:5, year:2021, counter:1},
    {month:6, year:2021, counter:1},
    {month:7, year:2021, counter:0},
    {month:8, year:2021, counter:1},
    {month:9, year:2021, counter:1},
    {month:10, year:2021, counter:1},
    {month:11, year:2021, counter:1},
    {month:12, year:2021, counter:0}
]
Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para lograr el resultado deseado, podemos hacer uso del framework de agregación de MongoDB. Específicamente, podemos utilizar las etapas del pipeline $match, $unwind, $project, $group y $sort para transformar los datos de entrada en el resultado deseado.

    Aquí está cómo se ve el pipeline:

    db.collection.aggregate([
      // filtrar los documentos sin historial
      {
        $match: {
          history: { $exists: true, $ne: [] }
        }
      },
      // desnormalizar el array de historial
      {
        $unwind: "$history"
      },
      // seleccionar solo los campos que necesitamos
      {
        $project: {
          _id: 0,
          month: { $month: "$history.date" },
          year: { $year: "$history.date" }
        }
      },
      // agrupar por mes y año, y contar el número de documentos
      {
        $group: {
          _id: { month: "$month", year: "$year" },
          count: { $sum: 1 }
        }
      },
      // ordenar por año y mes
      {
        $sort: {
          "_id.year": 1,
          "_id.month": 1
        }
      },
      // dar formato al resultado final
      {
        $project: {
          _id: 0,
          month: "$_id.month",
          year: "$_id.year",
          counter: "$count"
        }
      }
    ])
    

    Vamos a desglosarlo:

    1. La etapa $match filtra los documentos sin un array de historial.
    2. La etapa $unwind desnormaliza el array history en documentos separados.
    3. La etapa $project selecciona solo los campos que necesitamos, es decir, month y year.
    4. La etapa $group agrupa los documentos por month y year, y cuenta el número de documentos en cada grupo utilizando el acumulador $sum.
    5. La etapa $sort ordena la salida por year y month.
    6. La etapa $project da formato a la salida para que coincida con el formato del resultado deseado.

    La salida final es un array de objetos, donde cada objeto tiene los campos month, year y counter. El campo counter representa el número de elementos que tuvieron al menos una ocurrencia en ese mes.

    Ten en cuenta que el rango de meses y años en la salida dependerá del rango de fechas en los datos de entrada.

Comments are closed.