sql >> Databáze >  >> NoSQL >> MongoDB

$expr arrayElementAt nefunguje v agregaci pro vložený dokument

Rychlá oprava

Váš „potrubí“ zde nefunguje primárně protože váš počáteční $project chybí pole, které chcete použít v pozdější fázi. "rychlá oprava" je tedy v podstatě zahrnout toto pole do „projektovaného“ dokumentu, protože takto fungují fáze agregačního kanálu:

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
    )
  ),

Nebo dokonce od doby, kdy jste použili $$ROOT pro Student v každém případě jednoduše kvalifikujte pole pod touto cestou:

'$expr' => array(
  '$eq'=> array(
    array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
    $this->RoomId
  )
),

nicméně Důrazně* prosím, abyste NE udělejte to.

Celý koncept „zřetězení řetězců“ za účelem provedení pozdějšího $match na obsahu je opravdu špatný nápad, protože to znamená, že se celá sbírka přepíše v procesu, než se skutečně provede jakékoli „filtrování“.

Stejně tak je problém hledat shodu na "posledním" prvku pole. Mnohem lepší přístup je místo toho přidat „nové položky“ na „začátek“ pole, namísto „konce“. Toto je ve skutečnosti $position nebo možná i $sort modifikátory na $push udělat za vás změnou místa přidávání položek nebo seřazeného pořadí položek.

Změna pole na „nejnovější jako první“

To dá trochu práce tím, že změníte způsob ukládání věcí, ale výhodou je výrazně vyšší rychlost takových dotazů, jako chcete, aniž byste potřebovali vyhodnocený $expr argument.

Základním konceptem je „předpřipravit“ nové položky pole se syntaxí jako:

$this->collection->updateOne(
  $query,
  [ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
)

Kde $alloments musí být pole podle požadavků $each a $position se používá pro 0 za účelem přidání nové položky pole „první“.

Případně, pokud skutečně máte něco jako created_date jako vlastnost v rámci každého z objektů v poli, pak byste „mohli“ použít něco jako $sort jako modifikátor.

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

Opravdu záleží na tom, zda váš „dotaz“ a další požadavky na přístup spoléhají na „poslední přidání“ nebo „nejnovější datum“ a také obvykle, zda máte v úmyslu případně změnit takové created_date nebo jinou vlastnost "sort" způsobem, který by ovlivnil pořadí prvků pole při "třídění".

Důvod, proč to děláte, je, že shoda s „nejnovější“ (která je nyní „první“) položce v poli se jednoduše stane:

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

MongoDB umožňuje specifikovat „první“ index pole pomocí "Dot Notation" pomocí 0 index. Co nemůžete stačí zadat "negativní" index, tj.:

$this->collection->find([
 'allotment_details.-1.room_id': $this->RoomId  # not allowed :(
])

To je důvod, proč při „aktualizaci“ děláte věci uvedené výše, abyste „znovu uspořádali“ pole do funkční podoby.

Zřetězení je špatné

Dalším hlavním problémem je zřetězení řetězců. Jak již bylo zmíněno, vytváří to zbytečnou režii, jen aby bylo možné provést párování, které chcete. Je to také "zbytečné", protože se tomu můžete vyhnout pomocí $or s podmínkami v každém z polí, které již existují ve skutečném dokumentu:

 $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
 ])

A samozřejmě bez ohledu na to, jaké „úplné“ podmínky dotazu skutečně musí být, ale měli byste získat základní představu.

Také pokud ve skutečnosti nehledáte „částečná slova“, pak "textové vyhledávání" definované přes pole s "jmény". Po vytvoření indexu by to bylo:

 $this->collection->find([
   '$text' => [ '$search' => $arg ],
   'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
   'allotment_details.0.room_id': $this->RoomId
 ])

Celkově bych opravdu doporučil důkladně se podívat na všechny ostatní možnosti, spíše než provést jednu malou změnu ve vašem stávajícím kódu. S trochou pečlivé restrukturalizace toho, jak věci ukládáte a vlastně i „indexujete“, získáte obrovské výhody výkonu, které vaše rozsáhlé $concat přístup „hrubé síly“ prostě nemůže přinést.




  1. Měly by dva moduly používat stejné připojení redis? (Pracuji s Flaskem)

  2. Jak efektivně mazat dokumenty dotazem v mongo?

  3. Aktualizační objekt MongoDb v poli při prvním výskytu od posledního

  4. Agregační dotaz MongoDb s $group a $push do vnořeného dokumentu