Hurtig løsning
Din "pipeline" virker primært ikke her fordi dit første $project
mangler det felt, du ønsker at bruge på et senere tidspunkt. "hurtig rettelse" er derfor dybest set at inkludere det felt i det "projicerede" dokument, da det er sådan aggregeringspipeline stadier fungerer:
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
)
),
Eller endda siden du brugte $$ROOT
for Student
alligevel skal du blot kvalificere feltet under den sti:
'$expr' => array(
'$eq'=> array(
array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
$this->RoomId
)
),
dog Jeg ville stærkt* beder om, at du gør IKKE gør det.
Hele konceptet med "sammenkædning af strenge" for at lave en senere $match
på indholdet er en rigtig dårlig idé, da det betyder, at hele samlingen bliver omskrevet i pipelinen, før nogen "filtrering" rent faktisk bliver udført.
Ligeledes er det også et problem at se efter at matche på det "sidste" array-element. En langt bedre tilgang er i stedet faktisk at tilføje "nye elementer" til "begyndelsen" af arrayet i stedet for "slutningen". Dette er faktisk hvad $position
eller muligvis endda $sort
modifikatorer til $push
gøre for dig ved at ændre, hvor elementerne bliver tilføjet, eller den sorterede rækkefølge af varer.
Ændring af Array til "nyeste først"
Dette kræver lidt arbejde ved at ændre den måde, du gemmer ting på, men fordelene er en væsentligt forbedret hastighed af sådanne forespørgsler, som du ønsker, uden at du behøver en evalueret $expr
argument.
Kernekoncepterne er at "pre-pendere" nye array-elementer med syntaks som:
$this->collection->updateOne(
$query,
[ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)
Hvor $alloments
skal være et array som krævet af $each
og $position
bruges til 0
for at tilføje det nye array-element "først".
Alternativt hvis du faktisk har noget som created_date
som en egenskab inden for hvert af objekterne i arrayet, så "kunne" du bruge noget som $sort
som en modifikator i stedet.
$this->collection->updateOne(
$query,
[ '$push' => [
'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
]]
)
Det afhænger virkelig af, om din "forespørgsel" og andre adgangskrav er afhængige af "sidst tilføjet" eller "seneste dato", og så også typisk om du har til hensigt eventuelt at ændre en sådan created_date
eller anden "sort"-egenskab på en måde, som ville påvirke rækkefølgen af array-elementerne, når de "sorteres".
Grunden til at du gør dette, er at matche det "seneste" (som nu er det "første") element i arrayet bliver simpelthen:
$this->collection->find([
'allotment_details.0.room_id': $this->RoomId
])
MongoDB tillader det "første" array-indeks at blive specificeret med "Dot Notation"
, ved hjælp af 0
indeks. Hvad du ikke kan do er at angive et "negativt" indeks, dvs.:
$this->collection->find([
'allotment_details.-1.room_id': $this->RoomId # not allowed :(
])
Det er grunden til, at du gør de ting, der er vist ovenfor under "opdatering" for at "omorganisere" dit array til den brugbare form.
Sammenkædning er dårlig
Det andet hovedproblem er sammenkædningen af strenge. Som allerede nævnt skaber dette unødvendige overhead bare for at udføre den matchning, du ønsker. Det er også "unødvendigt", da du kan undgå dette ved at bruge $or
med betingelserne på hvert af felterne, som de allerede eksisterer i det aktuelle dokument:
$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
])
Og selvfølgelig hvad end de "fulde" forespørgselsbetingelser faktisk skal være, men du burde få den grundlæggende idé.
Også hvis du ikke rent faktisk leder efter "delord", så en "tekstsøgning" defineret over felterne med "navnene". Efter oprettelse af indekset ville det være:
$this->collection->find([
'$text' => [ '$search' => $arg ],
'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
'allotment_details.0.room_id': $this->RoomId
])
Generelt vil jeg virkelig anbefale at se nærmere på alle de andre muligheder i stedet for at foretage en lille ændring af din eksisterende kode. Med lidt omhyggelig omstrukturering af, hvordan du opbevarer ting og faktisk "indekserer" ting, får du enorme ydeevnefordele, som din omfattende $concat
"brute force"-tilgangen kan simpelthen ikke levere.