MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Regroupement de documents dans MongoDB sous condition particulière

Avis de non-responsabilité

Avant de lire le reste de la réponse, veuillez lire https://docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Le document résultant de la question devrait contenir un tableau de tous les documents appartenant à un groupe d'âge particulier.La taille de ce tableau ne peut pas dépasser 16 Mo , donc le code ci-dessous ne fonctionnera que pour de très petites collections de petits documents.

Le code :

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 partie qui peut nécessiter un peu d'explication est de savoir comment calculer les tranches d'âge.

Pour cela, nous obtenons tous les âges en utilisant $group dans un seul tableau, puis $addFields "ranges" - un tableau 2D de groupes d'âge avec des écarts entre la personne la plus âgée d'un groupe plus jeune et la personne la plus jeune du groupe plus âgé est supérieur à 2 ans.

Le tableau est calculé à l'aide de $reduce d'une $range tableau d'index de tous les âges sauf le premier, qui va à la valeur initiale.

L'expression de réduction est un $cond qui calcule la différence entre le courant et le précédent ($subtract ) élément du tableau de tous les âges.

S'il est supérieur à 2, un nouveau groupe d'âge est ajouté en utilisant $concatArrays . Sinon, l'âge est ajouté au groupe le plus ancien en utilisant $slice pour pousser jusqu'au dernier groupe dans le tableau des plages et $setUnion pour éliminer les doublons.

Lorsque les tranches d'âge sont calculées, nous $lookup la même collection par âge pour les regrouper dans le tableau "group".