MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

$expr arrayElementAt не работи при агрегиране за вграден документ

Бърза корекция

Вашият "тръбопровод" не работи тук основно защото вашият първоначален $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 за да добавите новия елемент от масива "първо".

Алтернативно, ако действително имате нещо като created_date като свойство във всеки от обектите в масива, тогава "можете" да използвате нещо като $sort вместо това като модификатор.

$this->collection->updateOne(
  $query,
  [ '$push' => [
      'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
  ]]
)

Това наистина зависи от това дали вашата „заявка“ и други изисквания за достъп разчитат на „последно добавено“ или „последна дата“, а след това също обикновено, ако възнамерявате евентуално да промените такава created_date или друго свойство за "сортиране" по начин, който би повлиял на реда на елементите на масива, когато са "сортирани".

Причината, поради която правите това, е след това съпоставянето на „последния“ (който сега е „първият“) елемент в масива просто става:

$this->collection->find([
 'allotment_details.0.room_id': $this->RoomId
])

MongoDB позволява "първият" индекс на масива да бъде определен с "Dot Notation" , използвайки 0 индекс. Каквоне можете do е да посочите "отрицателен" индекс, т.е.:

$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 подходът на "груба сила" просто не може да даде резултати.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Spring и MongoDB:SAXParseException при четене на Bean дефиниции

  2. ГРЕШКА:Не мога да запиша pid файл в /var/run/mongodb/mongod.pid:Няма такъв файл или директория inf fedora 20

  3. И оператор mongooastic (филтър)

  4. Премахване на дублиращи се записи с MapReduce

  5. Грешка при заявка за поддокументи на Mongodb Преобразуване на кръгова структура в JSON