MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Raggruppamento di documenti in MongoDB a condizioni speciali

Disclaimer

Prima di leggere il resto della risposta, leggi https://docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Il documento risultante nella domanda dovrebbe contenere un array di tutti i documenti che appartengono a un particolare gruppo di età.Le dimensioni di tale array non possono superare i 16 MB , quindi il codice seguente funzionerà solo per raccolte molto piccole di piccoli documenti.

Il codice:

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 che potrebbe richiedere un po' di spiegazione è come calcolare i gruppi di età.

Per questo, otteniamo tutte le età utilizzando $group in un singolo array e quindi $addFields "gamme" - una serie 2D di gruppi di età con differenze tra la persona più anziana in un gruppo più giovane e una persona più giovane nel gruppo più anziano è maggiore di 2 anni.

L'array viene calcolato utilizzando $reduce di un $range array di indici di tutte le età tranne il primo, che va al valore iniziale.

L'espressione reduce è un $cond che calcola la differenza tra corrente e precedente ($subtract ) elemento dell'array di tutte le età.

Se è maggiore di 2, viene aggiunta una nuova fascia di età utilizzando $concatArray . In caso contrario, l'età viene aggiunta al gruppo più anziano utilizzando $slice per eseguire il push all'ultimo gruppo nell'array ranges e $setUnion per eliminare i duplicati.

Quando vengono calcolate le fasce d'età, $lookup la stessa raccolta per età per raggrupparli nell'array "group".