MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

$expr arrayElementAt tidak berfungsi dalam agregasi untuk dokumen yang disematkan

Perbaikan cepat

"Pipa" Anda tidak berfungsi di sini terutama karena $project awal Anda tidak memiliki bidang yang ingin Anda gunakan di tahap selanjutnya. "Perbaikan cepat" oleh karena itu pada dasarnya untuk memasukkan bidang itu ke dalam dokumen "yang diproyeksikan", karena itulah cara kerja tahapan pipa agregasi:

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

Atau bahkan sejak Anda menggunakan $$ROOT untuk Siswa bagaimanapun, cukup kualifikasi bidang di bawah jalur itu:

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

namun Saya akan sangat* mohon agar Anda TIDAK lakukan itu.

Seluruh konsep "penggabungan string" untuk melakukan $cocok pada konten adalah ide yang sangat buruk karena itu berarti seluruh koleksi akan ditulis ulang dalam alur sebelum "pemfilteran" benar-benar dilakukan.

Demikian juga mencari kecocokan pada elemen array "terakhir" juga merupakan masalah. Pendekatan yang jauh lebih baik adalah dengan benar-benar menambahkan "item baru" ke "awal" array, alih-alih "akhir". Ini sebenarnya yang $position atau bahkan mungkin $sort pengubah ke $push lakukan untuk Anda, dengan mengubah tempat item ditambahkan atau urutan item yang diurutkan masing-masing.

Mengubah Array menjadi "terbaru dulu"

Ini membutuhkan sedikit kerja dengan mengubah cara Anda menyimpan sesuatu, tetapi manfaatnya adalah peningkatan kecepatan kueri seperti yang Anda inginkan tanpa memerlukan $expr yang dievaluasi argumen.

Konsep inti adalah untuk "menangguhkan" item array baru dengan sintaks seperti:

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

Dimana $alloments harus menjadi array seperti yang dipersyaratkan oleh $each dan $position digunakan untuk 0 untuk menambahkan item array baru "pertama".

Atau jika Anda benar-benar memiliki sesuatu seperti created_date sebagai properti di dalam setiap objek dalam array, maka Anda "bisa" menggunakan sesuatu seperti $sort sebagai pengubah.

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

Itu benar-benar tergantung pada apakah "kueri" Anda dan persyaratan akses lainnya bergantung pada "terakhir ditambahkan" atau "tanggal terbaru", dan kemudian juga biasanya jika Anda berniat untuk mengubah created_date tersebut. atau properti "sort" lainnya dengan cara yang akan mempengaruhi urutan elemen array saat "diurutkan".

Alasan Anda melakukan ini adalah mencocokkan item "terbaru" ( yang sekarang menjadi "pertama" ) dalam array menjadi:

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

MongoDB memungkinkan indeks array "pertama" ditentukan dengan "Notasi Titik" , menggunakan 0 indeks. Apa yang Anda tidak bisa lakukan adalah menentukan indeks "negatif" yaitu:

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

Itulah alasan mengapa Anda melakukan hal-hal yang ditunjukkan di atas pada "pembaruan" untuk "mengurutkan ulang" array Anda ke bentuk yang bisa diterapkan.

Penggabungan buruk

Masalah utama lainnya adalah penggabungan string. Seperti yang telah disebutkan, ini menciptakan overhead yang tidak perlu hanya untuk melakukan pencocokan yang Anda inginkan. Ini juga "tidak perlu" karena Anda dapat menyelesaikan menghindari ini menggunakan $or dengan kondisi pada masing-masing bidang seperti yang sudah ada dalam dokumen aktual:

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

Dan tentu saja, apa pun kondisi kueri "penuh" yang sebenarnya diperlukan, tetapi Anda harus mendapatkan ide dasarnya.

Juga jika Anda tidak benar-benar mencari "kata sebagian", maka "pencarian teks" didefinisikan di atas bidang dengan "nama". Setelah membuat indeks yang akan menjadi:

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

Secara keseluruhan, saya sangat merekomendasikan untuk melihat lebih dekat semua opsi lain daripada membuat satu perubahan kecil pada kode Anda yang ada. Dengan sedikit penataan ulang yang hati-hati tentang cara Anda menyimpan sesuatu dan memang "mengindeks" sesuatu, Anda mendapatkan manfaat kinerja yang sangat besar yang $concat ekstensif Anda Pendekatan "brute force" tidak bisa dilakukan.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Menanamkan balasan pesan di dalam pesan induk dengan mongodb menggunakan mongoid

  2. rmongodb:menggunakan $atau dalam kueri

  3. Bisakah seseorang membuat database relasional menggunakan MongoDB?

  4. bagaimana cara meneruskan variabel $tid, $id ke fungsi mentah?

  5. IdMemberMap adalah nol menggunakan Opsi Serialisasi Representasi