MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

ogranicz i posortuj każdą grupę według w mongoDB za pomocą agregacji

Najlepszą opcją jest tutaj uruchomienie oddzielnych zapytań dla każdego „Kraju” (najlepiej równolegle ) i zwrócenie połączonych wyników. Zapytania są dość proste i po prostu zwracają 2 najwyższe wartości po zastosowaniu sortowania według wartości oceny i będą wykonywane dość szybko, nawet jeśli musisz wykonać wiele zapytań, aby uzyskać pełny wynik.

Ramy agregacji nie są do tego odpowiednie, teraz, a nawet w najbliższej przyszłości. Problem w tym, że nie ma takiego operatora, który w jakikolwiek sposób „ogranicza” wynik dowolnego grupowania. Aby to zrobić, musisz w zasadzie $push całą zawartość do tablicy i wyodrębnij z niej „n górnych” wartości.

Obecne operacje potrzebne do tego są dość okropne, a głównym problemem jest to, że wyniki prawdopodobnie przekroczą limit 16 MB na dokument w przypadku większości rzeczywistych źródeł danych.

Istnieje również n złożoność tego ze względu na to, jak musiałbyś to zrobić teraz. Ale wystarczy zademonstrować z 2 przedmiotami:

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

Daje to wynik, ale nie jest to świetne podejście i staje się znacznie bardziej złożone z iteracjami dla wyższych limitów lub nawet tam, gdzie grupowanie ma prawdopodobnie mniej niż n wyniki zwracane w niektórych przypadkach.

Obecna seria rozwojowa ( 3.1.x ) od momentu pisania ma $slice operator, który czyni to nieco prostszym, ale nadal ma tę samą pułapkę „rozmiaru”:

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 w zasadzie dopóki struktura agregacji nie będzie miała sposobu na „ograniczenie” liczby elementów wytwarzanych przez $push lub podobny operator „limit” grupowania, wtedy struktura agregacji nie jest tak naprawdę optymalnym rozwiązaniem dla tego typu problemu.

Proste zapytania, takie jak:

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

Uruchom dla każdego odrębnego kraju i najlepiej w równoległym przetwarzaniu przez pętlę zdarzeń wątku z połączonym wynikiem, daje teraz najbardziej optymalne podejście. Pobierają tylko to, co jest potrzebne, co jest dużym problemem, z którym struktura agregacji nie może jeszcze poradzić sobie w takim grupowaniu.

Dlatego poszukaj wsparcia, aby wykonać te „połączone wyniki zapytań” w najbardziej optymalny sposób dla wybranego języka, ponieważ będzie to znacznie mniej złożone i znacznie bardziej wydajne niż rzucanie tego w ramach agregacji.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Pośrednia modyfikacja przeciążonej nieruchomości Laravel MongoDB

  2. Unikaj bieżącego parsera ciągu URL jest przestarzałe ostrzeżenie przez ustawienie useNewUrlParser na true

  3. Mongoose z unikalną wartością logiczną prawdy

  4. MongoDB Capped Collection nie usuwa dokumentów

  5. Jak zawrzeć tylko wybrany osadzony dokument w mongoengine?