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

$expr arrayElementAt nie działa w agregacji dla osadzonego dokumentu

Szybka naprawa

Twój „potok” nie działa tutaj głównie ponieważ twój początkowy $project brakuje pola, którego chcesz użyć na późniejszym etapie. „szybkie rozwiązanie” dlatego zasadniczo należy uwzględnić to pole w „projektowanym” dokumencie, ponieważ tak działają etapy potoku agregacji:

array(
  array(
    '$project' => array(
      'FullName' => array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
      'FirstMiddle' => array('$concat' => array('$first_name', ' ', '$middle_name')),
      'FirstLast' => array('$concat' => array('$first_name', ' ', '$last_name')),
      'FirstName' => array('$concat' => array('$first_name')),
      'MiddleName' => array('$concat' => array('$middle_name')),
      'LastName' => array('$concat' => array('$last_name')),
      'Student' => '$$ROOT',
      'allotment_details' => 1 # that's the change
    )
  ),

Lub nawet odkąd użyłeś $$ROOT dla Student w każdym razie po prostu zakwalifikuj pole pod tą ścieżką:

'$expr' => array(
  '$eq'=> array(
    array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
    $this->RoomId
  )
),

jednak Chciałbym zdecydowanie* błagaj, abyś NIE zrób to.

Cała koncepcja „łączenia ciągów” w celu późniejszego $match na treści jest naprawdę złym pomysłem, ponieważ oznacza to, że cała kolekcja zostanie przepisana w potoku, zanim jakiekolwiek "filtrowanie" zostanie faktycznie wykonane.

Problemem jest również szukanie dopasowania na „ostatnim” elemencie tablicy. O wiele lepszym podejściem jest zamiast tego faktyczne dodanie „nowych elementów” na „początku” tablicy, zamiast na „końcu”. To właśnie $position a może nawet $sort modyfikatory $push zrobić dla Ciebie, zmieniając odpowiednio miejsce dodawania elementów lub kolejność sortowania elementów.

Zmienianie tablicy na „najpierw najnowsze”

Zmiana sposobu przechowywania wymaga trochę pracy, ale korzyści to znacznie większa szybkość takich zapytań, jak chcesz, bez konieczności oceniania $expr argument.

Podstawowe koncepcje polegają na „wklejaniu” nowych elementów tablicy o składni takiej jak:

$this->collection->updateOne(
  $query,
  [ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)

Gdzie $alloments musi być tablicą zgodnie z wymaganiami $each i $position jest używany do 0 aby dodać nowy element tablicy "pierwszy".

Alternatywnie, jeśli faktycznie masz coś takiego jak created_date jako właściwość w każdym z obiektów w tablicy, możesz użyć czegoś takiego jak $sort jako modyfikator.

$this->collection->updateOne(
  $query,
  [ '$push' => [
      'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
  ]]
)

To naprawdę zależy od tego, czy twoje "zapytanie" i inne wymagania dostępu zależą od "ostatniej dodanej" czy "najnowszej daty", a także zazwyczaj, jeśli zamierzasz ewentualnie zmienić taką created_date lub inna właściwość „sort” w sposób, który wpłynie na kolejność elementów tablicy podczas „sortowania”.

Powodem, dla którego to robisz, jest dopasowanie "najnowszego" (który jest teraz "pierwszym" ) elementem tablicy po prostu staje się:

$this->collection->find([
 'allotment_details.0.room_id': $this->RoomId
])

MongoDB umożliwia określenie „pierwszego” indeksu tablicy za pomocą "Notacja kropkowa" , używając 0 indeks. Czego nie możesz do określa indeks „ujemny”, np.:

$this->collection->find([
 'allotment_details.-1.room_id': $this->RoomId  # not allowed :(
])

To jest powód, dla którego robisz rzeczy pokazane powyżej podczas „aktualizacji”, aby „zmienić kolejność” swojej tablicy na działającą formę.

Konkatenacja jest zła

Drugim głównym problemem jest konkatenacja ciągów. Jak już wspomniano, powoduje to niepotrzebne obciążenie tylko po to, aby wykonać dopasowanie, które chcesz. Jest to również „niepotrzebne”, ponieważ możesz tego uniknąć, używając $or z warunkami w każdym z pól, które istnieją już w rzeczywistym dokumencie:

 $this->collection->find([
   '$or' => [
       [ 'first_name' => new MongoDB\BSON\Regex($arg, 'i') ],
       [ 'last_name' => new MongoDB\BSON\Regex($arg, 'i') ],
       [ 'middle_name' => new MongoDB\BSON\Regex($arg, 'i') ],
       [ 'registration_temp_perm_no' => $arg ]
   ],
   'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
   'allotment_details.0.room_id': $this->RoomId
 ])

I oczywiście bez względu na to, jakie są „pełne” warunki zapytania, ale powinieneś poznać podstawową koncepcję.

Również jeśli nie szukasz „częściowych słów”, skorzystaj z "wyszukiwania tekstowego" zdefiniowane nad polami z „nazwami”. Po utworzeniu indeksu, który będzie:

 $this->collection->find([
   '$text' => [ '$search' => $arg ],
   'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
   'allotment_details.0.room_id': $this->RoomId
 ])

Ogólnie rzecz biorąc, naprawdę polecam przyjrzeć się wszystkim innym opcjom, zamiast wprowadzać jedną małą zmianę w istniejącym kodzie. Przy odrobinie starannej zmiany struktury sposobu przechowywania, a nawet „indeksowania” rzeczy, uzyskujesz ogromne korzyści w zakresie wydajności, które Twój rozbudowany $concat Podejście „brutalnej siły” po prostu nie może zapewnić.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. c# mongodb wyszukiwanie z uwzględnieniem wielkości liter

  2. Zarządzanie połączeniami Mongodb w Javie jako zorientowane obiektowo

  3. Wystąpił limit czasu po wybraniu serwera przez 30000 ms za pomocą CompositeServerSelector

  4. Jak uniknąć wielu procesów węzłowych wykonujących powtarzalne czynności?

  5. MongoDB:Pobieranie listy wszystkich baz danych?