Correção rápida
Seu "pipeline" não funciona aqui principalmente porque seu
$project
inicial
não possui o campo que você deseja usar em um estágio posterior. A "solução rápida" é, portanto, basicamente incluir esse campo no documento "projetado", pois é assim que os estágios do pipeline de agregação funcionam: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
)
),
Ou mesmo desde que você usou
$$ROOT
para Aluno
de qualquer forma, basta qualificar o campo nesse caminho:'$expr' => array(
'$eq'=> array(
array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
$this->RoomId
)
),
entretanto Eu fortemente* implorar que você NÃO faça isso.
Todo o conceito de "concatenar strings" para fazer um
$match
no conteúdo é uma ideia muito ruim, pois significa que toda a coleção é reescrita no pipeline antes que qualquer "filtragem" seja realmente feita. Da mesma forma, procurar corresponder no elemento "último" da matriz também é um problema. Uma abordagem muito melhor é adicionar "novos itens" ao "início" da matriz, em vez do "fim". Na verdade, é isso que o
$position
ou possivelmente até o $sort
modificadores para $push
fazer por você, alterando onde os itens são adicionados ou a ordem de classificação dos itens, respectivamente. Mudando o Array para "o mais novo primeiro"
Isso dá um pouco de trabalho alterando a maneira como você armazena as coisas, mas os benefícios são a velocidade muito melhorada de tais consultas, como você deseja, sem precisar de um
$expr
avaliado argumento. Os conceitos principais são "pré-anexar" novos itens de matriz com sintaxe como:
$this->collection->updateOne(
$query,
[ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)
Onde
$alloments
deve ser uma matriz conforme exigido por $each
e $position
é usado para 0
para adicionar o novo item da matriz "primeiro". Alternativamente, se você realmente tiver algo como
created_date
como uma propriedade dentro de cada um dos objetos na matriz, então você "poderia" usar algo como $sort
como um modificador em vez disso. $this->collection->updateOne(
$query,
[ '$push' => [
'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
]]
)
Realmente depende se sua "consulta" e outros requisitos de acesso dependem de "última adição" ou "última data", e também se você pretende possivelmente alterar tal
created_date
ou outra propriedade "sort" de uma forma que afetaria a ordem dos elementos da matriz quando "classificados". A razão pela qual você faz isso é corresponder ao item "latest" (que agora é o "first" ) na matriz simplesmente se torna:
$this->collection->find([
'allotment_details.0.room_id': $this->RoomId
])
O MongoDB permite que o "primeiro" índice de array seja especificado com "Dot Notation" , usando o
0
índice. O que você não pode fazer é especificar um índice "negativo", ou seja:$this->collection->find([
'allotment_details.-1.room_id': $this->RoomId # not allowed :(
])
Essa é a razão pela qual você faz as coisas mostradas acima em "atualizar" para "reordenar" sua matriz para a forma viável.
A concatenação é ruim
A outra questão principal é a concatenação de strings. Como já mencionado, isso cria uma sobrecarga desnecessária apenas para fazer a correspondência desejada. Também é "desnecessário", pois você pode evitar isso usando
$or
com as condições em cada um dos campos conforme já existem no documento real: $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
])
E, claro, o que quer que as condições de consulta "completas" realmente precisem ser, mas você deve ter a ideia básica.
Além disso, se você não estiver realmente procurando por "palavras parciais", então uma "text search" definido sobre os campos com os "nomes". Depois de criar o índice que seria:
$this->collection->find([
'$text' => [ '$search' => $arg ],
'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
'allotment_details.0.room_id': $this->RoomId
])
No geral, eu realmente recomendo olhar atentamente para todas as outras opções, em vez de fazer uma pequena alteração no seu código existente. Com uma pequena reestruturação cuidadosa de como você armazena as coisas e, de fato, "indexa" as coisas, você obtém enormes benefícios de desempenho que seu extenso
$concat
abordagem de "força bruta" simplesmente não pode entregar.