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

sortuj według wartości osadzonego obiektu w Mongodb

Jeśli musisz obliczyć coś takiego w czasie wykonywania, z „przefiltrowaną” zawartością z tablicy określającą porządek sortowania, najlepiej zrobić coś za pomocą .aggregate() aby zmienić kształt i określić wartość sortowania w ten sposób:

db.collection.aggregate([
    // Pre-filter the array elements
    { "$project": {
        "tags": 1,
        "score": {
            "$setDifference": [
                { "$map": {
                    "input": "$tags",
                    "as": "tag",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.id", "t1" ] },
                            "$$el.score",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    // Unwind to denormalize
    { "$unwind": "$score" },
    // Group back the "max" score
    { "$group": {
        "_id": "$_id",
        "tags": { "$first": "$tags" },
        "score": { "$max": "$score" }
    }},
    // Sort descending by score
    { "$sort": { "score": -1 } }
])

Gdzie pierwsza część potoku jest używana do "wstępnego filtrowania" zawartości tablicy (jak również do zachowania oryginalnego pola) tylko do tych wartości "score", gdzie id jest równe "t1". Odbywa się to poprzez przetwarzanie $map który stosuje warunek do każdego elementu przez $cond aby określić, czy zwrócić „wynik” dla tego elementu, czy false .

$setDifference operacja wykonuje porównanie z tablicą jednoelementową [false] który skutecznie usuwa wszystkie false wartości zwrócone z $map . Jako „zestaw” usuwa to również zduplikowane wpisy, ale dla celów sortowania jest to dobra rzecz.

Po zredukowaniu tablicy i zmianie jej kształtu na wartości, które przetwarzasz $unwind gotowy do następnego etapu, aby zająć się wartościami jako indywidualnymi elementami. $group etap zasadniczo dotyczy $max na "wyniku", aby zwrócić najwyższą wartość zawartą w przefiltrowanych wynikach.

Wtedy wystarczy tylko zastosować $sort od ustalonej wartości do zamówienia dokumentów. Oczywiście, jeśli chcesz to zrobić na odwrót, użyj $min i zamiast tego sortuj w porządku rosnącym.

Oczywiście dodaj $match etap do początku, jeśli wszystko, czego naprawdę potrzebujesz, to dokumenty, które faktycznie zawierają wartości "t1" dla id w obrębie tagów. Ale ta część ma najmniejsze znaczenie dla sortowania według przefiltrowanych wyników, które chcesz osiągnąć.

Alternatywą do obliczania jest robienie tego wszystkiego podczas wpisywania wpisów do tablicy w dokumentach. Trochę bałagan, ale wygląda mniej więcej tak:

db.collection.update(
    { "_id": docId },
    {
        "$push": { "tags": { "id": "t1", "score": 60 } },
        "$max": { "maxt1score": 60 },
        "$min": { "mint1score": 60 }
    }
)

Tutaj $max operator aktualizacji ustawia wartość dla określonego pola tylko wtedy, gdy nowa wartość jest większa niż istniejąca wartość lub w przeciwnym razie nie istnieje jeszcze żadna właściwość. Odwrotny przypadek dotyczy $min , gdzie tylko wtedy, gdy mniej niż zostanie zastąpione nową wartością.

To oczywiście skutkowałoby dodaniem różnych dodatkowych właściwości do dokumentów, ale końcowy wynik jest znacznie uproszczony sortowanie:

db.collection.find().sort({ "maxt1score": -1 })

I będzie działać znacznie szybciej niż obliczenia za pomocą potoku agregacji.

Zastanów się więc nad zasadami projektowania. Uporządkowane dane w tablicach, w których chcesz sortować wyniki filtrowane i sparowane, oznaczają obliczanie w czasie wykonywania w celu określenia, według której wartości należy sortować. Dodawanie dodatkowych właściwości do dokumentu w .update() oznacza, że ​​możesz po prostu odwołać się do tych właściwości w celu bezpośredniego sortowania wyników.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongoid:jak wykonać zapytanie dla wszystkich obiektów, w których wartość wynosi zero?

  2. Jak używać zmiennych z MongoDB $lookup

  3. Jak w NodeJS wyprowadzić wyniki z mongodb z różnymi nazwami pól?

  4. node.js mongojs findOne wywołanie zwrotne zwracające błąd jako null

  5. Ustaw domyślną datę w dokumencie Mongoose na teraz + [trochę przyrostu]