sql >> Databasteknik >  >> NoSQL >> MongoDB

Gruppering av dokument i MongoDB på särskilda villkor

Ansvarsfriskrivning

Innan du läser resten av svaret, läs https://docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Det resulterande dokumentet i frågan förväntas ha en uppsättning av alla dokument som tillhör en viss åldersgrupp.Storleken på den matrisen får inte överstiga 16 MB , så koden nedan fungerar endast för mycket små samlingar av små dokument.

Koden:

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

Den del som kan kräva lite förklaring är hur man räknar ut åldersgrupper.

För det får vi alla åldrar med $group i en enda array och sedan $addFields "intervall" - en 2D-uppsättning av åldersgrupper med klyftor mellan den äldsta personen i en yngre grupp och en yngst person i den äldre gruppen är större än 2 år.

Arrayen beräknas med $reduce av en $range array av index i alla åldrar men först, som går till initialt värde.

Reduceringsuttrycket är en $cond som beräknar skillnaden mellan nuvarande och tidigare ($subtract ) element i arrayen för alla åldrar.

Om den är större än 2 läggs en ny åldersgrupp till med $concatArrays . Annars läggs åldern till i den äldsta gruppen med $slice för att trycka till den sista gruppen i range-arrayen och $setUnion för att eliminera dubbletter.

När åldersgrupperna beräknas, $lookup samma samling efter ålder för att gruppera dem i "grupp"-arrayen.




  1. Hur frågar man MongoDB för att testa om en vara finns?

  2. Integrationstestning med Testcontainers + Quarkus + MongoDB

  3. Redis vs. Memcachad

  4. Hur FILTRER jag returnerad data mellan två datum från mongodb med hjälp av en aggregering:matchning, lookup och projekt?