Быстрое исправление
Ваш «конвейер» здесь не работает , прежде всего , потому что в вашем начальном $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
для добавления новый элемент массива "first".
С другой стороны, если у вас действительно есть что-то вроде created_date
в качестве свойства внутри каждого из объектов в массиве, тогда вы "можете" использовать что-то вроде $sort
в качестве модификатора.
$this->collection->updateOne(
$query,
[ '$push' => [
'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
]]
)
Это действительно зависит от того, зависят ли ваши «запрос» и другие требования доступа от «последнего добавления» или «последней даты», а также, как правило, от того, хотите ли вы изменить такое свойство created_date
или другое свойство «sort» в способ, который будет влиять на порядок элементов массива при "сортировке".
Причина, по которой вы делаете это, заключается в том, что элемент «последний» (который теперь является «первым») в массиве просто становится:
$this->collection->find([
'allotment_details.0.room_id': $this->RoomId
])
MongoDB позволяет указывать «первый» индекс массива с помощью «Точечная нотация» , используя индекс 0
. То, что вы не можете сделать, это указать «отрицательный» индекс, т.е.:
$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
подход «грубой силы».
N.B Современные версии PHP обычно поддерживают []
как гораздо более краткое представление array()
. Это намного чище и намного легче читать. Поэтому, пожалуйста, используйте его.