Snelle oplossing
Uw "pijplijn" werkt hier niet voornamelijk omdat uw initiële $project
mist het veld dat u later wilt gebruiken. De "snelle oplossing" is daarom eigenlijk om dat veld op te nemen in het "geprojecteerde" document, want zo werken aggregatiepijplijnfasen:
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
)
),
Of zelfs sinds je $$ROOT
. hebt gebruikt voor Student
hoe dan ook, kwalificeer gewoon het veld onder dat pad:
'$expr' => array(
'$eq'=> array(
array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
$this->RoomId
)
),
echter Ik zou sterk* smeek u dat u NIET . doet doe dat.
Het hele concept van "aaneenschakelen van strings" om een latere $match
op de inhoud is een heel slecht idee, omdat het betekent dat de hele collectie in de pijplijn wordt herschreven voordat er daadwerkelijk wordt 'gefilterd'.
Evenzo is het een probleem om te matchen op het "laatste" array-element. Een veel betere benadering is om in plaats daarvan "nieuwe items" toe te voegen aan het "begin" van de array, in plaats van aan het "einde". Dit is eigenlijk wat de $position
of mogelijk zelfs de $sort
modificaties voor $push
voor u doen, door respectievelijk te wijzigen waar items worden toegevoegd of de gesorteerde volgorde van items.
De array wijzigen in "nieuwste eerst"
Dit kost wat moeite door de manier waarop je dingen opslaat te veranderen, maar de voordelen zijn een sterk verbeterde snelheid van dergelijke zoekopdrachten zoals je wilt zonder dat een geëvalueerde $expr
nodig is. argument.
De kernconcepten zijn om nieuwe array-items "pre-pend" te maken met syntaxis zoals:
$this->collection->updateOne(
$query,
[ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)
Waar $alloments
moeten een array zijn zoals vereist door $each
en $position
wordt gebruikt om 0
om het nieuwe array-item "eerste" toe te voegen.
Of als u daadwerkelijk iets heeft als created_date
als een eigenschap binnen elk van de objecten in de array, dan "zou" u iets als $sort
in plaats daarvan als modifier.
$this->collection->updateOne(
$query,
[ '$push' => [
'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
]]
)
Het hangt er echt van af of uw "query" en andere toegangsvereisten afhankelijk zijn van "laatst toegevoegd" of "laatste datum", en dan meestal ook of u van plan bent zo'n created_date
mogelijk te wijzigen of een andere "sorteer"-eigenschap op een manier die de volgorde van de array-elementen zou beïnvloeden wanneer ze "gesorteerd" zijn.
De reden dat u dit doet, is dat het matchen van het "laatste" (wat nu het "eerste") item in de array is, eenvoudig wordt:
$this->collection->find([
'allotment_details.0.room_id': $this->RoomId
])
MongoDB staat toe dat de "eerste" array-index wordt gespecificeerd met "Dot Notation"
, met behulp van de 0
inhoudsopgave. Wat je niet kunt do is een "negatieve" index specificeren, d.w.z.:
$this->collection->find([
'allotment_details.-1.room_id': $this->RoomId # not allowed :(
])
Dat is de reden waarom je de dingen doet die hierboven bij "update" worden getoond om je array te "herordenen" naar de werkbare vorm.
Aaneenschakeling is slecht
Het andere belangrijke probleem is de aaneenschakeling van strings. Zoals eerder vermeld, creëert dit onnodige overhead om de gewenste matching te doen. Het is ook "onnodig", omdat je dit volledig kunt vermijden met $of
met de voorwaarden op elk van de velden zoals ze al bestaan in het eigenlijke document:
$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
])
En natuurlijk wat de "volledige" zoekvoorwaarden ook moeten zijn, maar u zou het basisidee moeten krijgen.
Ook als u niet echt op zoek bent naar "gedeeltelijke woorden", dan is een "text search" gedefinieerd over de velden met de "namen". Na het maken van de index zou dat zijn:
$this->collection->find([
'$text' => [ '$search' => $arg ],
'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
'allotment_details.0.room_id': $this->RoomId
])
Over het algemeen zou ik echt aanraden om goed naar alle andere opties te kijken in plaats van een kleine wijziging aan te brengen in je bestaande code. Met een beetje zorgvuldige herstructurering van hoe je dingen opslaat en inderdaad dingen "indexeert", krijg je enorme prestatievoordelen die je uitgebreide $concat
"brute force"-aanpak kan gewoon niet leveren.