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

begrænse og sortere hver gruppe efter i mongoDB ved hjælp af aggregering

Din bedste mulighed her er at køre separate forespørgsler for hvert "land" (ideelt parallelt) og returnere de kombinerede resultater. Forespørgslerne er ret enkle, og returnerer bare de øverste 2 værdier efter at have anvendt en sortering på vurderingsværdien og vil udføres ret hurtigt, selvom du skal udføre flere forespørgsler for at opnå det komplette resultat.

Aggregeringsrammen passer ikke godt til dette, nu og endda i den nærmeste fremtid. Problemet er, at der ikke er en sådan operatør, der "begrænser" resultatet af nogen gruppering på nogen måde. Så for at gøre dette, skal du dybest set $push alt indhold i en matrix og udtræk "top n" værdierne fra det.

De nuværende operationer, der er nødvendige for at gøre det, er temmelig forfærdelige, og kerneproblemet er, at resultaterne sandsynligvis vil overstige BSON-grænsen på 16 MB pr. dokument på de fleste rigtige datakilder.

Der er også en n kompleksiteten til dette på grund af, hvordan du skulle gøre det lige nu. Men lige for at demonstrere med 2 genstande:

db.collection.aggregate([
    // Sort content by country and rating
    { "$sort": { "Country": 1, "rating": -1 } },

    // Group by country and push all items, keeping first result
    { "$group": {
        "_id": "$Country",
        "results": {
            "$push": {
                "name": "$name", 
                "rating": "$rating",
                "id": "$id"
            }
        },
        "first": { 
            "$first": {
                "name": "$name", 
                "rating": "$rating",
                "id": "$id"
            }
        }
    }},

    // Unwind the array
    { "$unwind": "results" },

    // Remove the seen result from the array
    { "$redact": {
        "$cond": {
            "if": { "$eq": [ "$results.id", "$first.id" ] },
            "then": "$$PRUNE",
            "else": "$$KEEP"
        }
    }},

    // Group to return the second result which is now first on stack
    { "$group": {
        "_id": "$_id",
        "first": { "$first": "$first" },
        "second": { 
            "$first": {
                "name": "$results.name", 
                "rating": "$results.rating",
                "id": "$results.id"
            }
        }
    }},

    // Optionally put these in an array format
    { "$project": {
        "results": { 
            "$map": {
                "input": ["A","B"],
                "as": "el",
                "in": {
                    "$cond": {
                        "if": { "$eq": [ "$$el", "A" ] },
                        "then": "$first",
                        "else": "$second"
                    }
                }
            }
        }
    }}
])

Det giver resultatet, men det er ikke en god tilgang og bliver meget mere kompleks med iterationer for højere grænser eller endda hvor grupperinger muligvis har mindre end n resultater at vende tilbage i nogle tilfælde.

Den aktuelle udviklingsserie ( 3.1.x ) har i skrivende stund en $slice operator, der gør dette lidt mere enkelt, men stadig har den samme "størrelse" faldgrube:

db.collection.aggregate([
    // Sort content by country and rating
    { "$sort": { "Country": 1, "rating": -1 } },

    // Group by country and push all items, keeping first result
    { "$group": {
        "_id": "$Country",
        "results": {
            "$push": {
                "name": "$name", 
                "rating": "$rating",
                "id": "$id"
            }
        }
    }},
    { "$project": {
        "results": { "$slice": [ "$results", 2 ] }
    }}
])

Men dybest set indtil aggregeringsrammen har en måde at "begrænse" antallet af varer produceret af $push eller en lignende gruppering "grænse"-operatør, så er aggregeringsrammen ikke rigtig den optimale løsning til denne type problemer.

Enkle forespørgsler som denne:

db.collection.find({ "Country": "USA" }).sort({ "rating": -1 }).limit(1)

Kør for hvert enkelt land og ideelt set parallelt med bearbejdning af hændelsesløkke med et kombineret resultat giver den mest optimale tilgang lige nu. De henter kun det nødvendige, hvilket er det store problem, som aggregeringsrammen endnu ikke kan håndtere i en sådan gruppering.

Så søg efter støtte til at udføre disse "kombinerede forespørgselsresultater" på den mest optimale måde for dit valgte sprog i stedet, da det vil være langt mindre komplekst og meget mere effektivt end at kaste dette på aggregeringsrammen.




  1. Returner matrixelement efter indeks i en meteormellemrumsskabelon

  2. MongoDB - admin bruger ikke autoriseret

  3. Indsæt Array i eksisterende dokument

  4. Indsæt ordbog i MongoDB med c#-driver