Cakupan dan Penjelasan Umum
Ada beberapa hal yang salah dengan apa yang Anda lakukan di sini. Pertama, kondisi kueri Anda. Anda merujuk ke beberapa _id
nilai di mana Anda tidak perlu melakukannya, dan setidaknya salah satunya tidak berada di level teratas.
Untuk masuk ke nilai "bersarang" dan juga menganggap bahwa _id
nilainya unik dan tidak akan muncul di dokumen lain, formulir kueri Anda harus seperti ini:
Model.update(
{ "array1.array2._id": "123" },
{ "$push": { "array1.0.array2.$.answeredBy": "success" } },
function(err,numAffected) {
// something with the result in here
}
);
Sekarang itu benar-benar akan berhasil, tetapi sebenarnya itu hanya kebetulan karena ada alasan yang sangat bagus mengapa itu tidak berhasil untuk Anda.
Bacaan penting ada di dokumentasi resmi untuk posisi $
operator di bawah subjek "Array Bersarang". Apa yang tertulis di sini adalah:
Operator $ posisional tidak dapat digunakan untuk kueri yang melintasi lebih dari satu larik, seperti kueri yang melintasi larik bersarang di dalam larik lain, karena pengganti $ placeholder adalah nilai tunggal
Secara khusus yang dimaksud adalah elemen yang akan dicocokkan dan dikembalikan dalam placeholder posisional adalah nilai indeks dari pertama array yang cocok. Ini berarti dalam kasus Anda, indeks yang cocok pada larik tingkat "atas".
Jadi jika Anda melihat notasi kueri seperti yang ditunjukkan, kami telah "meng-hardcode" bagian pertama ( atau 0 index ) pada larik tingkat atas, dan kebetulan elemen yang cocok dalam "array2" juga merupakan entri indeks nol.
Untuk mendemonstrasikan ini, Anda dapat mengubah _id
yang cocok nilai ke "124" dan hasilnya akan $push
entri baru ke elemen dengan _id
"123" karena keduanya berada di entri indeks nol "array1" dan itu adalah nilai yang dikembalikan ke placeholder.
Jadi itulah masalah umum dengan array bersarang. Anda dapat menghapus salah satu level dan Anda masih dapat $push
ke elemen yang benar di larik "atas" Anda, tetapi masih akan ada beberapa level.
Cobalah untuk menghindari array bersarang karena Anda akan mengalami masalah pembaruan seperti yang ditunjukkan.
Kasus umum adalah untuk "meratakan" hal-hal yang Anda "pikir" adalah "tingkat" dan benar-benar membuat tesis "atribut" pada item detail akhir. Misalnya, bentuk struktur "rata" dalam pertanyaan harus seperti:
{
"answers": [
{ "by": "success", "type2": "123", "type1": "12" }
]
}
Atau bahkan ketika menerima array dalam adalah $push
saja, dan tidak pernah diperbarui:
{
"array": [
{ "type1": "12", "type2": "123", "answeredBy": ["success"] },
{ "type1": "12", "type2": "124", "answeredBy": [] }
]
}
Yang keduanya cocok untuk pembaruan atom dalam lingkup $
. posisional operator
MongoDB 3.6 ke atas
Dari MongoDB 3.6 ada fitur baru yang tersedia untuk bekerja dengan array bersarang. Ini menggunakan $[<identifier>]
. yang difilter posisi sintaks untuk mencocokkan elemen tertentu dan menerapkan kondisi yang berbeda melalui arrayFilters
dalam pernyataan pembaruan:
Model.update(
{
"_id": 1,
"array1": {
"$elemMatch": {
"_id": "12","array2._id": "123"
}
}
},
{
"$push": { "array1.$[outer].array2.$[inner].answeredBy": "success" }
},
{
"arrayFilters": [{ "outer._id": "12" },{ "inner._id": "123" }]
}
)
"arrayFilters"
seperti yang diteruskan ke opsi untuk .update()
atau bahkan.updateOne()
, .updateMany()
, .findOneAndUpdate()
atau .bulkWrite()
metode menentukan kondisi untuk dicocokkan dengan pengidentifikasi yang diberikan dalam pernyataan pembaruan. Setiap elemen yang cocok dengan kondisi yang diberikan akan diperbarui.
Karena strukturnya "bersarang", kami sebenarnya menggunakan "beberapa filter" seperti yang ditentukan dengan "array" definisi filter seperti yang ditunjukkan. "Pengidentifikasi" yang ditandai digunakan untuk mencocokkan dengan $[<identifier>]
yang difilter posisi sintaks sebenarnya digunakan di blok pembaruan pernyataan. Dalam hal ini inner
dan outer
adalah pengidentifikasi yang digunakan untuk setiap kondisi sebagaimana ditentukan dengan rantai bersarang.
Perluasan baru ini memungkinkan pembaruan konten array bersarang, tetapi tidak terlalu membantu dengan kepraktisan "meminta" data tersebut, jadi peringatan yang sama berlaku seperti yang dijelaskan sebelumnya.
Anda biasanya benar-benar "bermaksud" untuk menyatakan sebagai "atribut", bahkan jika otak Anda awalnya berpikir "bersarang", itu biasanya hanya reaksi terhadap bagaimana Anda percaya "bagian relasional sebelumnya" datang bersama-sama. Pada kenyataannya Anda benar-benar membutuhkan lebih banyak denormalisasi.
Lihat juga Cara Memperbarui Beberapa Elemen Array di mongodb, karena operator pembaruan baru ini sebenarnya cocok dan memperbarui "beberapa elemen array" daripada hanya pertama , yang merupakan tindakan pembaruan posisi sebelumnya.
CATATAN Agak ironis, karena ini ditentukan dalam argumen "opsi" untuk
.update()
dan seperti metode, sintaks umumnya kompatibel dengan semua versi driver rilis terbaru.Namun ini tidak berlaku untuk
mongo
shell, karena cara metode ini diterapkan di sana ( "ironisnya untuk kompatibilitas ke belakang" )arrayFilters
argumen tidak dikenali dan dihapus oleh metode internal yang mem-parsing opsi untuk memberikan "kompatibilitas mundur" dengan versi server MongoDB sebelumnya dan.update()
"warisan" Sintaks panggilan API.Jadi jika Anda ingin menggunakan perintah di
mongo
shell atau produk "berbasis shell" lainnya (terutama Robo 3T ) Anda memerlukan versi terbaru baik dari cabang pengembangan atau rilis produksi mulai 3.6 atau lebih tinggi.
Lihat juga positional all $[]
yang juga memperbarui "beberapa elemen larik" tetapi tanpa menerapkan kondisi tertentu dan berlaku untuk semua elemen dalam array di mana itu adalah tindakan yang diinginkan.