sql >> Databáze >  >> NoSQL >> MongoDB

Seskupování dokumentů v MongoDB za zvláštních podmínek

Odmítnutí odpovědnosti

Než si přečtete zbytek odpovědi, přečtěte si prosím https://docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Očekává se, že výsledný dokument v otázce bude obsahovat pole všech dokumentů, které patří do určité věkové skupiny.Velikost tohoto pole nesmí přesáhnout 16 MB , takže níže uvedený kód bude fungovat pouze pro velmi malé kolekce malých dokumentů.

Kód:

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 } }
])

Část, která může vyžadovat trochu vysvětlení, je způsob výpočtu věkových skupin.

Za tímto účelem získáváme všechny věkové skupiny pomocí $group do jednoho pole a poté $addFields "rozsahy" - 2D pole věkových skupin s mezerami mezi nejstarší osobou v mladší skupině a nejmladší osobou ve starší skupině je větší než 2 roky.

Pole se vypočítá pomocí $reduce z rozsah $ pole indexů všech věkových kategorií kromě prvního, které přejde na počáteční hodnotu.

Výraz snížení je $cond který vypočítá rozdíl mezi aktuálním a předchozím ($subtract ) prvek pole všech věkových kategorií.

Pokud je větší než 2, přidá se nová věková skupina pomocí $concatArrays . Jinak je věk přidán do nejstarší skupiny pomocí $slice přesunout do poslední skupiny v poli rozsahů a $setUnion k odstranění duplicit.

Po výpočtu věkových skupin $lookup stejnou kolekci podle věku a seskupit je do pole "group".




  1. Použití redis s node.js (expresní)

  2. C# + MongoDB - ObjectId bez použití datových typů/atributů MongoDB

  3. MongoDB - Import CSV do vnořeného dokumentu

  4. Vraťte výsledky mongoose ve vyhledávacím dotazu do proměnné