sql >> Base de Datos >  >> NoSQL >> MongoDB

Agrupación de documentos en MongoDB en condiciones especiales

Descargo de responsabilidad

Antes de leer el resto de la respuesta, lea https://docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Se espera que el documento resultante en la pregunta tenga una matriz de todos los documentos que pertenecen a un grupo de edad particular.El tamaño de esa matriz no puede exceder los 16 MB , por lo que el siguiente código funcionará solo para colecciones muy pequeñas de documentos diminutos.

El código:

db.collection.aggregate([
    { $sort: { age: 1 } },
    { $group: {
            _id: null,
            ages: { $push: "$age" }
    } },
    { $addFields: {
        ranges: { $reduce: { 
            input: { $range: [ 1, { $size: "$ages" }, 1 ] }, 
            initialValue: [ [ { $arrayElemAt: [ "$ages", 0 ] } ] ], 
            in: { $cond: { 
                if:  { $gt: [
                    { $subtract: [ { $arrayElemAt: [ "$ages", "$$this" ] }, { $arrayElemAt: [ "$ages", { $subtract: [ "$$this", 1 ] } ] } ] },
                    2
                    ] }, 
                then: { $concatArrays: [ "$$value",  [ [ { $arrayElemAt: [ "$ages", "$$this" ] } ] ] ] }, 
                else: { $concatArrays: [ 
                    { $slice: [ "$$value" , { $subtract: [ { $size: "$$value" }, 1 ] } ] },
                    [ { $concatArrays: [ 
                        { $arrayElemAt: [ { $slice: [ "$$value" , -1 ] }, 0 ] }  ,  
                        [ { $arrayElemAt: [ "$ages", "$$this" ] } ]
                    ]  } ]
                ] }
            } }
        } } 
    } },
    { $unwind: "$ranges" }, 
    { $lookup: {
       from: "collection",
       localField: "ranges",
       foreignField: "age",
       as: "group"
     } },
     { $project: { _id: 0, group: 1 } }
])

La parte que puede requerir un poco de explicación es cómo calcular los grupos de edad.

Para eso, obtenemos todas las edades usando $group en una sola matriz y luego $addFields "rangos":una matriz 2D de grupos de edad con brechas entre la persona mayor en un grupo más joven y una persona más joven en el grupo mayor es mayor a 2 años.

La matriz se calcula usando $reduce de un $range conjunto de índices de todas las edades excepto el primero, que va al valor inicial.

La expresión de reducción es un $cond que calcula la diferencia entre el actual y el anterior ($subtract ) elemento de la matriz de todas las edades.

Si es mayor a 2, se agrega un nuevo grupo de edad usando $concatArreglos . De lo contrario, la edad se agrega al grupo más antiguo usando $slice para pasar al último grupo en la matriz de rangos y $setUnion para eliminar duplicados.

Cuando se calculan los grupos de edad, $lookup la misma colección por edad para agruparlos en la matriz "grupo".