Schnelle Lösung
Ihre "Pipeline" funktioniert hier hauptsächlich nicht weil Ihr anfänglicher $project
Ihnen fehlt das Feld, das Sie zu einem späteren Zeitpunkt verwenden möchten. Die "schnelle Lösung" ist es daher grundsätzlich, dieses Feld in das "projizierte" Dokument aufzunehmen, da die Phasen der Aggregationspipeline so funktionieren:
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
)
),
Oder sogar seit Sie $$ROOT
verwendet haben für Schüler
qualifizieren Sie trotzdem einfach das Feld unter diesem Pfad:
'$expr' => array(
'$eq'=> array(
array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
$this->RoomId
)
),
jedoch Ich würde dringend* beschwören Sie, dass Sie es NICHT tun mach das.
Das gesamte Konzept des „Verkettens von Zeichenfolgen“, um später einen $übereinstimmung
auf den Inhalt ist eine wirklich schlechte Idee, da dies bedeutet, dass die gesamte Sammlung in der Pipeline neu geschrieben wird, bevor tatsächlich eine "Filterung" durchgeführt wird.
Ebenso ist es auch ein Problem, nach Übereinstimmungen mit dem "letzten" Array-Element zu suchen. Ein weitaus besserer Ansatz besteht darin, stattdessen "neue Elemente" am "Anfang" des Arrays anstelle am "Ende" hinzuzufügen. Das ist eigentlich das, was der $position
oder möglicherweise sogar der $sort
Modifikatoren zu $push
tun, indem Sie ändern, wo Elemente hinzugefügt werden, bzw. die sortierte Reihenfolge der Elemente.
Änderung des Arrays auf "neueste zuerst"
Dies erfordert ein wenig Arbeit, da Sie die Art und Weise ändern, wie Sie Dinge speichern, aber die Vorteile sind eine stark verbesserte Geschwindigkeit solcher Abfragen, wie Sie es möchten, ohne dass ein ausgewerteter $expr
erforderlich ist Argument.
Die Kernkonzepte bestehen darin, neue Array-Elemente mit Syntax wie:
voranzustellen$this->collection->updateOne(
$query,
[ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)
Wobei $alloments
müssen ein Array sein, wie von $each
gefordert
und $position
wird zu 0
verwendet um das neue Array-Element "first" hinzuzufügen.
Alternativ, wenn Sie tatsächlich so etwas wie created_date
haben als Eigenschaft in jedem der Objekte im Array "könnten" Sie so etwas wie $sort
stattdessen als Modifikator.
$this->collection->updateOne(
$query,
[ '$push' => [
'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
]]
)
Es hängt wirklich davon ab, ob Ihre "Abfrage" und andere Zugriffsanforderungen auf "zuletzt hinzugefügt" oder "neuestes Datum" basieren, und dann auch normalerweise, wenn Sie beabsichtigen, ein solches created_date
möglicherweise zu ändern oder eine andere "sortieren"-Eigenschaft in einer Weise, die die Reihenfolge der Array-Elemente beeinflussen würde, wenn sie "sortiert" werden.
Der Grund, warum Sie dies tun, ist, dass der Abgleich des "neuesten" (das jetzt das "erste") Element im Array einfach zu:
wird$this->collection->find([
'allotment_details.0.room_id': $this->RoomId
])
MongoDB ermöglicht die Angabe des "ersten" Array-Index mit "Dot Notation"
, indem Sie 0
verwenden Index. Was Sie nicht können Geben Sie einen "negativen" Index an, z. B.:
$this->collection->find([
'allotment_details.-1.room_id': $this->RoomId # not allowed :(
])
Das ist der Grund, warum Sie die oben gezeigten Dinge auf "Aktualisieren" tun, um Ihr Array in die funktionsfähige Form "umzuordnen".
Verkettung ist schlecht
Das andere Hauptproblem ist die Verkettung von Zeichenfolgen. Wie bereits erwähnt, erzeugt dies unnötigen Overhead, nur um das gewünschte Matching durchzuführen. Es ist auch "unnötig", da Sie dies mit $oder
vollständig vermeiden können mit den Bedingungen für jedes der Felder, wie sie bereits im eigentlichen Dokument vorhanden sind:
$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
])
Und natürlich, was auch immer die "vollständigen" Abfragebedingungen tatsächlich sein müssen, aber Sie sollten die Grundidee verstehen.
Auch wenn Sie nicht wirklich nach "Teilwörtern" suchen, dann eine "Textsuche" über die Felder mit den "Namen" definiert. Nach dem Erstellen des Index wäre das:
$this->collection->find([
'$text' => [ '$search' => $arg ],
'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
'allotment_details.0.room_id': $this->RoomId
])
Insgesamt würde ich wirklich empfehlen, sich alle anderen Optionen genau anzusehen, anstatt eine kleine Änderung an Ihrem vorhandenen Code vorzunehmen. Mit ein wenig sorgfältiger Neustrukturierung der Art und Weise, wie Sie Dinge speichern und tatsächlich "indizieren", erhalten Sie enorme Leistungsvorteile gegenüber Ihrem umfangreichen $concat
"Brute-Force"-Ansatz kann einfach nicht liefern.