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

Filtruj wyniki według wartości pola ostatniego wpisu w tablicy

Przebieg może się na tym różnić i może się okazać, że „obecnie” proces, który realizujesz, jest przynajmniej „najbardziej dopasowany”. Ale prawdopodobnie możemy działać wydajniej.

Co możesz teraz zrobić

Pod warunkiem, że twoje tablice są już "posortowane" za pomocą $sortuj modyfikator z $push , prawdopodobnie możesz to zrobić:

db.somedb.find(
  { 
    "partn.is_partner": true,
    "$where": function() {
      return this.partn.slice(-1)[0].is_partner == true;
    }
  },
  { "partn": { "$slice": -1 } }
)

Tak długo, jak partn,is_partner jest „indeksowany”, jest to nadal dość wydajne, ponieważ początkowy warunek zapytania można spełnić za pomocą indeksu. Część, która nie może, to $where tutaj klauzula, która używa oceny JavaScript.

Ale co ta druga część w $where robi to po prostu "wycinanie" ostatniego elementu z tablicy i testowanie jego wartości is_partner właściwość, aby sprawdzić, czy to prawda. Tylko wtedy, gdy ten warunek jest spełniony, dokument zostanie zwrócony.

Istnieje również $slice operator projekcji. Robi to samo przy zwrocie ostatniego elementu z tablicy. Fałszywe dopasowania są już filtrowane, więc pokazuje tylko ostatni element, w którym jest prawdziwe.

W połączeniu z indeksem, jak wspomniano, powinno to być dość szybkie, biorąc pod uwagę, że dokumenty zostały już wybrane, a warunek JavaScript tylko filtruje resztę. Zauważ, że bez innego pola ze standardowym warunkiem zapytania do dopasowania, $where klauzula nie może używać indeksu. Dlatego zawsze staraj się używać "oszczędnie" z innymi warunkami zapytania.

Co możesz zrobić w przyszłości

Następna w kolejce, chociaż nie jest dostępna w momencie pisania tego tekstu, ale na pewno w niedalekiej przyszłości będzie $slice operator dla struktury agregacji. Jest to obecnie w branży deweloperskiej, ale oto, jak to działa:

db.somedb.aggregate([
  { "$match": { "partn.is_partner": true } },
  { "$redact": {
    "$cond": {
      "if": { 
        "$anyElementTrue": {
          "$map": {
            "input": { "$slice": ["$partn",-1] },
            "as": "el",
            "in": "$$el.is_partner"
          }
        }
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }},
  { "$project": {
      "partn": { "$slice": [ "$partn",-1 ] }
  }}
])

Łączenie tego $slice w $redact etap tutaj umożliwia filtrowanie dokumentów za pomocą warunku logicznego, testując dokument. W tym przypadku $slice tworzy jednoelementową tablicę, która jest wysyłana do $ mapa aby po prostu wyodrębnić pojedynczy is_partner wartość (nadal jako tablica). Ponieważ w najlepszym przypadku jest to tablica jednoelementowa, drugi test to $anyElementTrue co sprawia, że ​​jest to pojedynczy wynik logiczny, odpowiedni dla $przewód .

$redact tutaj decyduje o tym wyniku, czy $$ZACHOWAJ lub $$PRUNE dokument z wyników. Później używamy $slice ponownie w projekcie, aby po prostu zwrócić ostatni element tablicy po filtrowaniu.

Wygląda na to, że jest to dokładnie to samo, co robi wersja JavaScript, z wyjątkiem tego, że używa wszystkich natywnych operatorów kodowanych i dlatego powinno być nieco szybsze niż alternatywa JavaScript.

Oba formularze zwracają pierwszy dokument zgodnie z oczekiwaniami:

{
    "_id" : 0,
    "partn" : [
            {
                    "date" : ISODate("2015-07-28T00:59:14.963Z"),
                    "is_partner" : true
            },
            {
                    "date" : ISODate("2015-07-28T01:00:32.771Z"),
                    "is_partner" : false
            },
            {
                    "date" : ISODate("2015-07-28T01:15:29.916Z"),
                    "is_partner" : true
            },
            {
                    "date" : ISODate("2015-08-05T13:48:07.035Z"),
                    "is_partner" : false
            },
            {
                    "date" : ISODate("2015-08-05T13:50:56.482Z"),
                    "is_partner" : true
            }
    ]
}

Dużym haczykiem w obu przypadkach jest to, że twoja tablica musi być już posortowana, więc najnowsza data jest pierwsza. Bez tego potrzebujesz struktury agregacji do $sort tablicę, tak jak teraz.

Niezbyt wydajne, dlatego powinieneś „wstępnie posortować” swoją tablicę i zachować porządek przy każdej aktualizacji.

Jako poręczna sztuczka, to faktycznie zmieni kolejność wszystkich elementów tablicy we wszystkich dokumentach kolekcji w jednej prostej instrukcji:

db.somedb.update(
    {},
    { "$push": { 
        "partn": { "$each": [], "$sort": { "date": 1 } }
    }},
    { "multi": true }
)

Więc nawet jeśli nie „wpychasz” nowego elementu do tablicy i tylko aktualizujesz właściwość, zawsze możesz zastosować tę podstawową konstrukcję, aby utrzymać porządek w tablicy, jak chcesz.

Warto rozważyć, ponieważ powinno to znacznie przyspieszyć.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB Jak wykonać zapytanie za pomocą operatora $date?

  2. Jak modelować wiele autoreferencyjnych relacji z wieloma rodzicami?

  3. Pobierz n-ty element tablicy w MongoDB

  4. mongodb sprawdza wyrażenie regularne na polach z jednej kolekcji do wszystkich pól w innej kolekcji

  5. Zaktualizuj obiekt wewnątrz tablicy w mongoDb za pomocą mongoose