Saya punya dokumen Mongo yang menampung berbagai elemen.
Saya ingin mengatur ulang .handled
atribut semua objek dalam array di mana .profile
= XX.
Dokumen tersebut dalam bentuk berikut:
{
"_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
"user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
"events": [{
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 20,
"data": "....."
}
...
]
}
jadi, saya mencoba yang berikut ini:
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
Namun itu hanya memperbarui elemen array yang cocok pertama di setiap dokumen. (Itulah perilaku yang ditentukan untuk $ - operator posisi .)
Bagaimana cara saya memperbarui semua elemen array yang cocok?
arrays
mongodb
mongodb-query
LiorH
sumber
sumber
Jawaban:
Pada saat ini tidak mungkin untuk menggunakan operator posisi untuk memperbarui semua item dalam sebuah array. Lihat JIRA http://jira.mongodb.org/browse/SERVER-1243
Sebagai pekerjaan di sekitar Anda dapat:
sumber
Dengan rilis MongoDB 3.6 (dan tersedia di cabang pengembangan dari MongoDB 3.5.12) sekarang Anda dapat memperbarui beberapa elemen array dalam satu permintaan.
Ini menggunakan sintaksis operator pembaruan posisional yang disaring yang
$[<identifier>]
diperkenalkan dalam versi ini:The
"arrayFilters"
sebagai diteruskan ke pilihan untuk.update()
atau bahkan.updateOne()
,.updateMany()
,.findOneAndUpdate()
atau.bulkWrite()
metode menspesifikasikan kondisi untuk mencocokkan pada identifier yang diberikan dalam pernyataan update. Elemen apa pun yang cocok dengan kondisi yang diberikan akan diperbarui.Memperhatikan bahwa
"multi"
seperti yang diberikan dalam konteks pertanyaan digunakan dengan harapan bahwa ini akan "memperbarui banyak elemen" tetapi ini tidak dan masih tidak demikian. Penggunaannya di sini berlaku untuk "banyak dokumen" seperti yang selalu terjadi atau sekarang dinyatakan sebagai pengaturan wajib.updateMany()
dalam versi API modern.Lihat juga
positional all $[]
yang juga memperbarui "beberapa elemen array" tetapi tanpa menerapkan kondisi yang ditentukan dan berlaku untuk semua elemen dalam array yang merupakan tindakan yang diinginkan.Juga lihat Memperbarui Array Bertingkat dengan MongoDB untuk bagaimana operator posisi baru ini berlaku untuk struktur array "bersarang", di mana "array berada dalam array lain".
sumber
elem
?arrayFilters
, jadi jalankan pembaruan melalui CLI. stackoverflow.com/questions/48322834/…Apa yang berhasil bagi saya adalah ini:
Saya pikir ini lebih jelas untuk pemula mongo dan siapa pun yang akrab dengan JQuery & friends.
sumber
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
dan mendapatkanOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Saya ingin melakukan pembaruan ini langsung dari mongo shell tanpa menggunakan Javascript API.Ini juga dapat dilakukan dengan loop sementara yang memeriksa untuk melihat apakah ada dokumen yang masih memiliki sub dokumen yang belum diperbarui. Metode ini menjaga keaslian pembaruan Anda (yang tidak banyak solusi lain di sini).
Jumlah kali loop dieksekusi akan sama dengan jumlah maksimum kali sub dokumen dengan
profile
sama dengan 10 danhandled
tidak sama dengan 0 terjadi di salah satu dokumen dalam koleksi Anda. Jadi, jika Anda memiliki 100 dokumen dalam koleksi Anda dan salah satunya memiliki tiga sub dokumen yang cocokquery
dan semua dokumen lainnya memiliki lebih sedikit sub dokumen yang cocok, loop akan dijalankan tiga kali.Metode ini menghindari bahaya mengalahkan data lain yang mungkin diperbarui oleh proses lain saat skrip ini dijalankan. Ini juga meminimalkan jumlah data yang ditransfer antara klien dan server.
sumber
Ini sebenarnya terkait dengan masalah lama di http://jira.mongodb.org/browse/SERVER-1243 di mana sebenarnya ada sejumlah tantangan untuk sintaks yang jelas yang mendukung "semua kasus" di mana pertandingan array mutiple berada ditemukan. Sebenarnya ada metode yang sudah ada yang "membantu" dalam solusi untuk masalah ini, seperti Operasi Massal yang telah dilaksanakan setelah posting asli ini.
Masih tidak mungkin untuk memperbarui lebih dari satu elemen array yang cocok dalam satu pernyataan pembaruan tunggal, sehingga bahkan dengan pembaruan "multi" semua yang dapat Anda perbarui hanyalah satu elemen matematika dalam array untuk setiap dokumen dalam satu dokumen itu dalam satu pernyataan.
Solusi terbaik yang mungkin saat ini adalah menemukan dan mengulang semua dokumen yang cocok dan memproses pembaruan Massal yang setidaknya akan memungkinkan banyak operasi dikirim dalam satu permintaan dengan respons tunggal. Secara opsional Anda dapat menggunakan
.aggregate()
untuk mengurangi konten array yang dikembalikan dalam hasil pencarian hanya untuk mereka yang cocok dengan kondisi untuk pemilihan pembaruan:The
.aggregate()
porsi akan bekerja ketika ada "unik" pengidentifikasi untuk array atau semua konten untuk setiap elemen membentuk "unik" elemen itu sendiri. Ini disebabkan oleh operator "set" yang$setDifference
digunakan untuk memfilterfalse
nilai yang dikembalikan dari$map
operasi yang digunakan untuk memproses array untuk pertandingan.Jika konten array Anda tidak memiliki elemen unik, Anda dapat mencoba pendekatan alternatif dengan
$redact
:Di mana batasannya adalah bahwa jika "ditangani" sebenarnya suatu bidang dimaksudkan untuk hadir di tingkat dokumen lain, maka Anda kemungkinan akan mendapatkan hasil yang tidak terduga, tetapi baik-baik saja di mana bidang itu hanya muncul di satu posisi dokumen dan merupakan pencocokan kesetaraan.
Rilis di masa mendatang (pos 3.1 MongoDB) pada saat penulisan akan memiliki
$filter
operasi yang lebih sederhana:Dan semua rilis yang mendukung
.aggregate()
dapat menggunakan pendekatan berikut$unwind
, tetapi penggunaan operator itu menjadikannya pendekatan yang paling tidak efisien karena ekspansi array di dalam pipa:Dalam semua kasus di mana versi MongoDB mendukung "kursor" dari output agregat, maka ini hanya masalah memilih pendekatan dan mengulangi hasilnya dengan blok kode yang sama yang ditunjukkan untuk memproses pernyataan pembaruan Massal. Operasi Massal dan "kursor" dari output agregat diperkenalkan dalam versi yang sama (MongoDB 2.6) dan oleh karena itu biasanya bekerja bergandengan tangan untuk diproses.
Pada versi yang bahkan lebih awal maka mungkin yang terbaik adalah hanya menggunakan
.find()
untuk mengembalikan kursor, dan menyaring eksekusi pernyataan hanya berapa kali elemen array cocok dengan.update()
iterasi:Jika Anda secara tegas bertekad untuk melakukan pembaruan "multi" atau menganggap itu pada akhirnya lebih efisien daripada memproses beberapa pembaruan untuk setiap dokumen yang cocok, maka Anda selalu dapat menentukan jumlah maksimum pencocokan array yang mungkin dan hanya menjalankan pembaruan "banyak" yang banyak kali, hingga pada dasarnya tidak ada lagi dokumen untuk diperbarui.
Pendekatan yang valid untuk versi MongoDB 2.4 dan 2.2 juga dapat digunakan
.aggregate()
untuk menemukan nilai ini:Apa pun masalahnya, ada hal-hal tertentu yang tidak ingin Anda lakukan dalam pembaruan:
Jangan "satu tembakan" memperbarui array: Di mana jika Anda berpikir mungkin lebih efisien untuk memperbarui seluruh konten array dalam kode dan kemudian hanya
$set
seluruh array dalam setiap dokumen. Ini mungkin tampak lebih cepat untuk diproses, tetapi tidak ada jaminan bahwa konten array tidak berubah sejak dibaca dan pembaruan dilakukan. Meskipun$set
masih merupakan operator atom, itu hanya akan memperbarui array dengan apa yang "dianggapnya" adalah data yang benar, dan dengan demikian kemungkinan akan menimpa setiap perubahan yang terjadi antara baca dan tulis.Jangan menghitung nilai indeks yang akan diperbarui: Jika mirip dengan pendekatan "satu tembakan", Anda hanya menentukan posisi
0
dan posisi itu2
(dan seterusnya) adalah elemen untuk memperbarui dan kode ini dengan dan pada akhirnya pernyataan seperti:Sekali lagi masalah di sini adalah "anggapan" bahwa nilai-nilai indeks yang ditemukan ketika dokumen dibaca adalah nilai indeks yang sama dalam array pada saat pembaruan. Jika item baru ditambahkan ke array dengan cara yang mengubah urutan maka posisi tersebut tidak lagi valid dan item yang salah sebenarnya diperbarui.
Jadi sampai ada sintaks yang masuk akal ditentukan untuk memungkinkan beberapa elemen array yang cocok untuk diproses dalam pernyataan pembaruan tunggal maka pendekatan dasar adalah baik memperbarui setiap elemen array yang cocok dalam pernyataan indvidual (idealnya dalam Massal) atau pada dasarnya bekerja di luar elemen array maksimum untuk memperbarui atau terus memperbarui hingga tidak ada lagi hasil yang dimodifikasi yang dikembalikan. Bagaimanapun, Anda harus "selalu" memproses pembaruan posisi
$
pada elemen array yang cocok, bahkan jika itu hanya memperbarui satu elemen per pernyataan.Operasi Massal sebenarnya adalah solusi "umum" untuk memproses setiap operasi yang berhasil menjadi "beberapa operasi", dan karena ada lebih banyak aplikasi untuk ini daripada sekadar memperbarui elemen array mutiple dengan nilai yang sama, maka tentu saja telah diimplementasikan sudah, dan saat ini merupakan pendekatan terbaik untuk menyelesaikan masalah ini.
sumber
Saya kagum ini masih belum ditangani di mongo. Secara keseluruhan mongo sepertinya tidak terlalu bagus ketika berhadapan dengan sub-array. Misalnya, Anda tidak dapat menghitung sub-array.
Saya menggunakan solusi pertama Javier. Baca larik ke dalam acara, lalu lewati dan buat set exp:
Ini dapat diabstraksi menjadi fungsi menggunakan panggilan balik untuk pengujian bersyarat
sumber
Saya telah mencari solusi untuk ini menggunakan driver terbaru untuk C # 3.6 dan inilah perbaikan yang akhirnya saya setujui. Kuncinya di sini adalah menggunakan "$ []" yang menurut MongoDB baru pada versi 3.6. Lihat https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] untuk informasi lebih lanjut.
Berikut kodenya:
Untuk lebih banyak konteks lihat posting asli saya di sini: Hapus elemen array dari SEMUA dokumen menggunakan driver MongoDB C #
sumber
Utasnya sudah sangat lama, tetapi saya datang mencari jawaban di sini sehingga memberikan solusi baru.
Dengan MongoDB versi 3.6+, sekarang memungkinkan untuk menggunakan operator posisi untuk memperbarui semua item dalam sebuah array. Lihat dokumentasi resmi di sini .
Permintaan berikut akan berfungsi untuk pertanyaan yang diajukan di sini. Saya juga telah memverifikasi dengan driver Java-MongoDB dan berhasil.
Semoga ini bisa membantu orang seperti saya.
sumber
Saya mencoba yang berikut dan ini berfungsi dengan baik.
// fungsi panggilan balik dalam kasus nodejs
sumber
Anda dapat memperbarui semua elemen di MongoDB
Ini akan memperbarui semua nilai "status" menjadi "selesai" di Array "arr"
Jika Hanya satu dokumen
Tetapi jika tidak satu dan Anda tidak ingin semua dokumen dalam array diperbarui maka Anda perlu untuk mengulang elemen dan di dalam blok if
sumber
Sebenarnya, perintah save hanya pada instance dari kelas dokumen. Itu memiliki banyak metode dan atribut. Jadi, Anda dapat menggunakan fungsi lean () untuk mengurangi beban kerja. Rujuk ke sini. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
Masalah lain dengan fungsi save, yang akan membuat data konflik dengan multi-save pada saat yang sama. Model.Update akan membuat data secara konsisten. Jadi untuk memperbarui banyak item dalam array dokumen. Gunakan bahasa pemrograman yang Anda kenal dan coba sesuatu seperti ini, saya menggunakan luwak dalam hal itu:
sumber
operator $ [] memilih semua array bersarang .. Anda dapat memperbarui semua item array dengan '$ []'
Referensi
sumber
$[]
hanya memperbarui semua bidang dalam array yang ditentukan. Yang berfungsi adalah operator posisi yang difilter$[identifier]
yang operator pada bidang array yang cocok dengan kondisi yang ditentukan. Harus digunakan denganarrayFilters
Refrence: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters dan docs.mongodb.com/manual/reference/operator/update/…Perlu diketahui bahwa beberapa jawaban di utas ini menyarankan penggunaan $ [] SALAH.
Kode di atas akan memperbarui "ditangani" ke 0 untuk semua elemen dalam array "acara", terlepas dari nilai "profil" -nya. Permintaan
{"events.profile":10}
hanya untuk memfilter seluruh dokumen, bukan dokumen dalam array. Dalam situasi ini adalah suatu keharusan untuk digunakan$[elem]
denganarrayFilters
menentukan kondisi item array sehingga jawaban Neil Lunn benar.sumber
Perbarui bidang array dalam banyak dokumen di mongo db.
Gunakan $ pull atau $ push dengan memperbarui banyak kueri untuk memperbarui elemen array di mongoDb.
sumber
Pertama: kode Anda tidak berfungsi karena Anda menggunakan operator posisional
$
yang hanya mengidentifikasi elemen untuk diperbarui dalam array tetapi bahkan tidak secara eksplisit menentukan posisinya dalam array.Yang Anda butuhkan adalah operator posisi yang difilter
$[<identifier>]
. Itu akan memperbarui semua elemen yang cocok dengan kondisi filter array.Larutan:
Kunjungi mongodb doc di sini
Apa yang dilakukan kode:
{"events.profile":10}
memfilter koleksi Anda dan mengembalikan dokumen yang cocok dengan filterThe
$set
pembaruan Operator: memodifikasi pencocokan bidang dokumen itu bekerja pada.{multi:true}
Itu membuat.update()
memodifikasi semua dokumen yang cocok dengan filter sehingga berperilaku sepertiupdateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
Teknik ini melibatkan penggunaan array posisi yang difilter dengan arrayFilters. array posisi yang difilter di sini$[elem]
bertindak sebagai pengganti untuk semua elemen dalam bidang array yang cocok dengan kondisi yang ditentukan dalam filter array.Filter array
sumber