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ć.