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

Gruppering af dokumenter i MongoDB på speciel betingelse

Ansvarsfraskrivelse

Før du læser resten af ​​svaret, bedes du læse https://docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Det resulterende dokument i spørgsmålet forventes at have en matrix af alle dokumenter, der tilhører en bestemt aldersgruppe.Størrelsen af ​​denne matrix må ikke overstige 16 MB , så koden nedenfor fungerer kun for meget små samlinger af små dokumenter.

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, der kan kræve lidt forklaring, er, hvordan man beregner aldersgrupper.

Til det får vi alle aldre ved at bruge $group ind i et enkelt array og derefter $addFields "intervaller" - en 2D-array af aldersgrupper med afstanden mellem den ældste person i en yngre gruppe og en yngste person i den ældre gruppe er større end 2 år.

Arrayet beregnes ved hjælp af $reduce af en $range række af indekser i alle aldre, men først, som går til startværdi.

Reduceringsudtrykket er en $cond som beregner forskel mellem nuværende og tidligere ($subtract ) element i rækken af ​​alle aldre.

Hvis den er større end 2, tilføjes en ny aldersgruppe ved hjælp af $concatArrays . Ellers føjes alderen til den ældste gruppe ved hjælp af $slice for at skubbe til den sidste gruppe i ranges-arrayet og $setUnion for at eliminere dubletter.

Når aldersgrupperne beregnes, $lookup den samme samling efter alder for at gruppere dem i "gruppe"-arrayet.




  1. De tre A'er for MongoDB Security - Autentificering, autorisation og revision

  2. meteor/mongodb:Brug forskellige DB til godkendelse og læs/skriv

  3. Mongoose String til ObjectID

  4. MongoDB ORM til Python?