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

omezit a seřadit každou skupinu podle v mongoDB pomocí agregace

Nejlepší možností je spustit samostatné dotazy pro každou "Země" (ideálně paralelně) a vrátit kombinované výsledky. Dotazy jsou poměrně jednoduché a po použití řazení na hodnotu hodnocení stačí vrátit 2 nejvyšší hodnoty a provedou se poměrně rychle, i když k získání úplného výsledku potřebujete provést více dotazů.

Agregační rámec se k tomu nehodí, a to ani nyní, ani v blízké budoucnosti. Problém je v tom, že neexistuje žádný takový operátor, který by nějakým způsobem „omezoval“ výsledek jakéhokoli seskupování. Takže abyste to mohli udělat, musíte v podstatě $push veškerý obsah do pole a extrahujte z něj „horních n“ hodnot.

Současné operace, které jsou k tomu zapotřebí, jsou dost hrozné a hlavním problémem je, že výsledky pravděpodobně překročí limit BSON 16 MB na dokument u většiny skutečných zdrojů dat.

Existuje také n složitost kvůli tomu, jak byste to museli udělat právě teď. Ale jen pro demonstraci pomocí 2 položek:

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

To dostane výsledek, ale není to skvělý přístup a je mnohem složitější s iteracemi pro vyšší limity nebo dokonce tam, kde seskupení mají možná méně než n výsledky se v některých případech vrátí.

Aktuální vývojová řada (3.1.x) má v době psaní $slice operátor, díky kterému je to o něco jednodušší, ale stále má stejnou "velikost" úskalí:

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

Ale v zásadě dokud nebude mít agregační rámec nějaký způsob, jak „omezit“ počet položek produkovaných $push nebo podobný operátor „limit“ seskupení, pak agregační rámec není skutečně optimálním řešením pro tento typ problému.

Jednoduché dotazy, jako je tento:

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

Běh pro každou jednotlivou zemi a ideálně paralelní zpracování pomocí smyčky událostí vlákna s kombinovaným výsledkem vytváří právě teď nejoptimálnější přístup. Přinesou pouze to, co je potřeba, což je velký problém, který agregační rámec v takovém seskupování zatím nedokáže zvládnout.

Hledejte tedy podporu, abyste mohli tyto „kombinované výsledky dotazů“ provádět nejoptimálnějším způsobem pro vámi zvolený jazyk, protože to bude mnohem méně složité a mnohem výkonnější, než když to házíte do agregačního rámce.




  1. Jaká je výhoda shlukování Redis na různých hostitelích?

  2. Jmenné prostory v Redis?

  3. Podpora rozsahu v průběhu času

  4. Existuje podpora ovladače mongodb C# System.Dynamic.DynamicObject v .NET 4?