Бърза корекция
Вашият "тръбопровод" не работи тук основно защото вашият първоначален $project
липсва полето, което искате да използвате на по-късен етап. "Бързата корекция" следователно основно е да включите това поле в „проектирания“ документ, тъй като така работят етапите на тръбопровода за агрегиране:
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
)
),
Или дори след като сте използвали $$ROOT
за Student
както и да е, просто квалифицирайте полето под този път:
'$expr' => array(
'$eq'=> array(
array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
$this->RoomId
)
),
обаче Бих силно* умолявам да правите НЕ направи това.
Цялата концепция за „конкатениране на низове“, за да се направи по-късен $match
върху съдържанието е наистина лоша идея, тъй като това означава, че цялата колекция се пренаписва в процеса, преди каквото и да е „филтриране“ действително да бъде извършено.
По същия начин търсенето на съответствие на "последния" елемент от масива също е проблем. Много по-добър подход е вместо това всъщност да добавите "нови елементи" към "началото" на масива, вместо към "края". Това всъщност е $position
или евентуално дори $sort
модификатори на $push
правят вместо вас, като променят мястото, където се добавят елементи или съответно сортирания ред на елементите.
Промяна на масива на „първо най-новите“
Това изисква малко работа, като промените начина, по който съхранявате неща, но предимствата са значително подобрена скорост на такива заявки, каквито искате, без да е необходим оценен $expr
аргумент.
Основните концепции са "предварително добавяне" на нови елементи от масив със синтаксис като:
$this->collection->updateOne(
$query,
[ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)
Където $alloments
задължително да бъде масив, както се изисква от $each
и $position
се използва за 0
за да добавите новия елемент от масива "първо".
Алтернативно, ако действително имате нещо като created_date
като свойство във всеки от обектите в масива, тогава "можете" да използвате нещо като $sort
вместо това като модификатор.
$this->collection->updateOne(
$query,
[ '$push' => [
'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
]]
)
Това наистина зависи от това дали вашата „заявка“ и други изисквания за достъп разчитат на „последно добавено“ или „последна дата“, а след това също обикновено, ако възнамерявате евентуално да промените такава created_date
или друго свойство за "сортиране" по начин, който би повлиял на реда на елементите на масива, когато са "сортирани".
Причината, поради която правите това, е след това съпоставянето на „последния“ (който сега е „първият“) елемент в масива просто става:
$this->collection->find([
'allotment_details.0.room_id': $this->RoomId
])
MongoDB позволява "първият" индекс на масива да бъде определен с "Dot Notation"
, използвайки 0
индекс. Каквоне можете do е да посочите "отрицателен" индекс, т.е.:
$this->collection->find([
'allotment_details.-1.room_id': $this->RoomId # not allowed :(
])
Това е причината, поради която правите нещата, показани по-горе при „актуализиране“, за да „пренаредите“ масива си в работеща форма.
Свързването е лошо
Другият основен проблем е конкатенацията на низове. Както вече споменахме, това създава ненужни режийни разходи, само за да направите съвпадението, което искате. Освен това е „ненужно“, тъй като можете напълно да избегнете това с $or
с условията за всяко от полетата, тъй като те вече съществуват в действителния документ:
$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
])
И, разбира се, каквито и да са "пълните" условия на заявката, но трябва да разберете основната идея.
Освен това, ако всъщност не търсите „частични думи“, тогава "текстово търсене" определени над полетата с "имена". След създаването на индекса това ще бъде:
$this->collection->find([
'$text' => [ '$search' => $arg ],
'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
'allotment_details.0.room_id': $this->RoomId
])
Като цяло наистина бих препоръчал да разгледате внимателно всички други опции, вместо да правите една малка промяна в съществуващия си код. С малко внимателно преструктуриране на начина, по който съхранявате нещата и наистина „индексирате“ нещата, вие получавате огромни предимства в производителността, отколкото вашият обширни $concat
подходът на "груба сила" просто не може да даде резултати.