Cara Memperbarui Beberapa Elemen Array di mongodb

183

Saya punya dokumen Mongo yang menampung berbagai elemen.

Saya ingin mengatur ulang .handledatribut 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?

LiorH
sumber
2
Memperbarui subset atau semua item array telah ditambahkan ke mongodb 3.6: docs.mongodb.com/manual/reference/operator/update/…
Jaap
pastikan untuk memeriksa arrayFilters dan pertimbangkan kueri mana yang digunakan untuk membuat pembaruan menjadi efisien. Lihatlah jawabannya oleh Neil Lunn: stackoverflow.com/a/46054172/337401
Jaap
periksa jawaban saya
Ucdemir

Jawaban:

111

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:

  • Perbarui setiap item secara individual (events.0.handled events.1.handled ...) atau ...
  • Baca dokumen, lakukan pengeditan secara manual dan simpan menggantikan yang lebih lama (centang "Perbarui jika Saat Ini" jika Anda ingin memastikan pembaruan atom)
Javier Ferrero
sumber
15
jika Anda memiliki masalah yang serupa, berikan
LiorH
Saya sebenarnya suka membaca dokumen dan menyimpan pendekatan. Tapi saya menggunakan Couch sebelum Mongo sehingga pendekatan itu tampak lebih alami karena tidak ada API permintaan untuk Couch, hanya api REST untuk seluruh dokumen
adam
1
Kedua pendekatan ini membutuhkan jumlah memori yang cukup tinggi, bukan? Jika ada banyak dokumen yang harus dicari, dan harus memuat semuanya (atau array bersarang) untuk memperbarui ... + juga agak sulit untuk diterapkan jika ini harus dilakukan secara tidak sinkron ...
Ixx
13
Selain semua kesulitan teknis, agak mengherankan bahwa fitur ini tidak tersedia di MongoDB. Kendala ini menghilangkan banyak kebebasan dari menyesuaikan skema database.
Sung Cho
5
Neil Lunn stackoverflow.com/a/46054172/337401 menjawab ini untuk versi 3.6. Karena ini adalah pertanyaan yang populer, mungkin perlu untuk memperbarui jawaban yang diterima ini dengan referensi ke jawaban oleh Neil Lunn.
Jaap
73

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:

db.collection.update(
  { "events.profile":10 },
  { "$set": { "events.$[elem].handled": 0 } },
  { "arrayFilters": [{ "elem.profile": 10 }], "multi": true }
)

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.

CATATAN Agak ironisnya, karena ini ditentukan dalam argumen "opsi" untuk .update()dan seperti metode, sintaksis umumnya kompatibel dengan semua versi driver rilis terbaru.

Namun ini tidak benar dari mongoshell, karena cara metode ini diterapkan di sana ("ironisnya untuk kompatibilitas mundur") arrayFiltersargumen tidak diakui dan dihapus oleh metode internal yang mem-parsing opsi untuk memberikan "kompatibilitas mundur" dengan sebelumnya Versi server MongoDB dan .update()sintaksis panggilan API "lawas" .

Jadi jika Anda ingin menggunakan perintah di mongoshell atau produk "berbasis shell" lainnya (terutama Robo 3T), Anda memerlukan versi terbaru dari cabang pengembangan atau rilis produksi 3,6 atau lebih tinggi.

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".

PENTING - Instalasi yang ditingkatkan dari versi sebelumnya "mungkin" belum mengaktifkan fitur MongoDB, yang juga dapat menyebabkan pernyataan gagal. Anda harus memastikan prosedur pemutakhiran Anda lengkap dengan perincian seperti peningkatan indeks dan kemudian jalankan

   db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )

Atau versi yang lebih tinggi sebagaimana berlaku untuk versi yang Anda instal. yaitu "4.0"untuk versi 4 dan seterusnya saat ini. Ini mengaktifkan fitur seperti operator pembaruan posisi baru dan lainnya. Anda juga dapat memeriksa dengan:

   db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

Untuk mengembalikan pengaturan saat ini

Neil Lunn
sumber
9
Jawaban yang diterima harus diperbarui dan merujuk ke jawaban ini.
Jaap
2
Apa elem?
user1063287
1
Ini benar. Perhatikan bahwa RoboMongo belum mendukung arrayFilters, jadi jalankan pembaruan melalui CLI. stackoverflow.com/questions/48322834/…
drlff
terima kasih, Neil, terutama untuk bagian PENTING, persis apa yang saya butuhkan
janfabian
kode ini mengembalikan ERROR dalam pymongo. ada kesalahan: naikkan TypeError ("% s harus Benar atau Salah"% (opsi,)) TypeError: upert harus Benar atau Salah
Vagif
67

Apa yang berhasil bagi saya adalah ini:

db.collection.find({ _id: ObjectId('4d2d8deff4e6c1d71fc29a07') })
  .forEach(function (doc) {
    doc.events.forEach(function (event) {
      if (event.profile === 10) {
        event.handled=0;
      }
    });
    db.collection.save(doc);
  });

Saya pikir ini lebih jelas untuk pemula mongo dan siapa pun yang akrab dengan JQuery & friends.

Daniel Cerecedo
sumber
Saya menggunakan db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...dan mendapatkanOops.. TypeError: Object # has no method 'forEach'
Squirrl
3
@Squirrl bisa jadi versi mongodb yang ketinggalan zaman? Dokumen ini jelas tentang cara menerapkan fungsi forEach pada kursor tetapi tidak menyatakan sejak versi mana yang didukung. docs.mongodb.org/manual/reference/method/cursor.forEach
Daniel Cerecedo
@Squirrl trydb.posts.find(...).toArray().forEach(...)
marmor
Bisakah kita melakukan ini tanpa menggunakan Javascript? Saya ingin melakukan pembaruan ini langsung dari mongo shell tanpa menggunakan Javascript API.
Meliodas
1
Bisakah Anda menulis kueri ini di driver mongodb untuk java atau dengan spring-data-mongodb? Terima kasih, kris
chiku
18

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

var query = {
    events: {
        $elemMatch: {
            profile: 10,
            handled: { $ne: 0 }
        }
    }
};

while (db.yourCollection.find(query).count() > 0) {
    db.yourCollection.update(
        query,
        { $set: { "events.$.handled": 0 } },
        { multi: true }
    );
}

Jumlah kali loop dieksekusi akan sama dengan jumlah maksimum kali sub dokumen dengan profilesama dengan 10 dan handledtidak 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.

Sean
sumber
13

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:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$project": {
        "events": {
            "$setDifference": [
               { "$map": {
                   "input": "$events",
                   "as": "event",
                   "in": {
                       "$cond": [
                           { "$eq": [ "$$event.handled", 1 ] },
                           "$$el",
                           false
                       ]
                   }
               }},
               [false]
            ]
        }
    }}
]).forEach(function(doc) {
    doc.events.forEach(function(event) {
        bulk.find({ "_id": doc._id, "events.handled": 1  }).updateOne({
            "$set": { "events.$.handled": 0 }
        });
        count++;

        if ( count % 1000 == 0 ) {
            bulk.execute();
            bulk = db.collection.initializeOrderedBulkOp();
        }
    });
});

if ( count % 1000 != 0 )
    bulk.execute();

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 $setDifferencedigunakan untuk memfilter falsenilai yang dikembalikan dari $mapoperasi yang digunakan untuk memproses array untuk pertandingan.

Jika konten array Anda tidak memiliki elemen unik, Anda dapat mencoba pendekatan alternatif dengan $redact:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$redact": {
        "$cond": {
            "if": {
                "$eq": [ { "$ifNull": [ "$handled", 1 ] }, 1 ]
            },
            "then": "$$DESCEND",
            "else": "$$PRUNE"
        }
    }}
])

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 $filteroperasi yang lebih sederhana:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$project": {
        "events": {
            "$filter": {
                "input": "$events",
                "as": "event",
                "cond": { "$eq": [ "$$event.handled", 1 ] }
            }
        }
    }}
])

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:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$unwind": "$events" },
    { "$match": { "events.handled": 1 } },
    { "$group": {
        "_id": "$_id",
        "events": { "$push": "$events" }
    }}        
])

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:

db.collection.find({ "events.handled": 1 }).forEach(function(doc){ 
    doc.events.filter(function(event){ return event.handled == 1 }).forEach(function(event){
        db.collection.update({ "_id": doc._id },{ "$set": { "events.$.handled": 0 }});
    });
});

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:

var result = db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$unwind": "$events" },
    { "$match": { "events.handled": 1 } },
    { "$group": {
        "_id": "$_id",
        "count": { "$sum": 1 }
    }},
    { "$group": {
        "_id": null,
        "count": { "$max": "$count" }
    }}
]);

var max = result.result[0].count;

while ( max-- ) {
    db.collection.update({ "events.handled": 1},{ "$set": { "events.$.handled": 0 }},{ "multi": true })
}

Apa pun masalahnya, ada hal-hal tertentu yang tidak ingin Anda lakukan dalam pembaruan:

  1. Jangan "satu tembakan" memperbarui array: Di mana jika Anda berpikir mungkin lebih efisien untuk memperbarui seluruh konten array dalam kode dan kemudian hanya $setseluruh 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 $setmasih 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.

  2. Jangan menghitung nilai indeks yang akan diperbarui: Jika mirip dengan pendekatan "satu tembakan", Anda hanya menentukan posisi 0dan posisi itu 2(dan seterusnya) adalah elemen untuk memperbarui dan kode ini dengan dan pada akhirnya pernyataan seperti:

    { "$set": {
        "events.0.handled": 0,
        "events.2.handled": 0
    }}

    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.

Blakes Seven
sumber
8

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:

var set = {}, i, l;
for(i=0,l=events.length;i<l;i++) {
  if(events[i].profile == 10) {
    set['events.' + i + '.handled'] = 0;
  }
}

.update(objId, {$set:set});

Ini dapat diabstraksi menjadi fungsi menggunakan panggilan balik untuk pengujian bersyarat

lebih lanjut
sumber
Terima kasih untuk ini! Tidak percaya fitur ini masih belum didukung secara asli! Digunakan ini untuk meningkatkan setiap item dari subarray, untuk yang lain membaca ... untuk memperbarui setiap item hanya menghapus pernyataan if.
Zaheer
9
Ini bukan solusi yang aman. Jika catatan ditambahkan saat Anda menjalankan pembaruan, Anda akan merusak data Anda.
Merc
4

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:

{
   var filter = Builders<Scene>.Filter.Where(i => i.ID != null);
   var update = Builders<Scene>.Update.Unset("area.$[].discoveredBy");
   var result = collection.UpdateMany(filter, update, new UpdateOptions { IsUpsert = true});
}

Untuk lebih banyak konteks lihat posting asli saya di sini: Hapus elemen array dari SEMUA dokumen menggunakan driver MongoDB C #

C0d3 0n3
sumber
4

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.

.update(   // or updateMany directly, removing the flag for 'multi'
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},  // notice the empty brackets after '$' opearor
   false,
   true
)

Semoga ini bisa membantu orang seperti saya.

ersnh
sumber
1

Saya mencoba yang berikut dan ini berfungsi dengan baik.

.update({'events.profile': 10}, { '$set': {'events.$.handled': 0 }},{ safe: true, multi:true }, callback function);

// fungsi panggilan balik dalam kasus nodejs

Pranay Saha
sumber
Kode ini baru saja memperbarui item yang cocok pertama dalam array. Jawaban yang salah.
Hamlett
Ini berfungsi untuk v2.6. Anda mungkin berada di versi yang lebih lama? Inilah dokumennya docs.mongodb.com/manual/reference/method/db.collection.update/…
Jialin Zou
1

Anda dapat memperbarui semua elemen di MongoDB

db.collectioname.updateOne(
{ "key": /vikas/i },
{ $set: { 
 "arr.$[].status" : "completed"
} }
)

Ini akan memperbarui semua nilai "status" menjadi "selesai" di Array "arr"

Jika Hanya satu dokumen

db.collectioname.updateOne(
 { key:"someunique", "arr.key": "myuniq" },
 { $set: { 
   "arr.$.status" : "completed", 
   "arr.$.msgs":  {
                "result" : ""
        }
   
 } }
)

Tetapi jika tidak satu dan Anda tidak ingin semua dokumen dalam array diperbarui maka Anda perlu untuk mengulang elemen dan di dalam blok if

db.collectioname.find({findCriteria })
  .forEach(function (doc) {
    doc.arr.forEach(function (singlearr) {
      if (singlearr check) {
        singlearr.handled =0
      }
    });
    db.collection.save(doc);
  });
VIKAS KOHLI
sumber
0

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:

User.findOne({'_id': '4d2d8deff4e6c1d71fc29a07'}).lean().exec()
  .then(usr =>{
    if(!usr)  return
    usr.events.forEach( e => {
      if(e && e.profile==10 ) e.handled = 0
    })
    User.findOneAndUpdate(
      {'_id': '4d2d8deff4e6c1d71fc29a07'},
      {$set: {events: usr.events}},
      {new: true}
    ).lean().exec().then(updatedUsr => console.log(updatedUsr))
})
pengguna3176403
sumber
0

operator $ [] memilih semua array bersarang .. Anda dapat memperbarui semua item array dengan '$ []'

.update({"events.profile":10},{$set:{"events.$[].handled":0}},false,true)

Referensi

Ucdemir
sumber
Bisakah Anda jelaskan mengapa Anda memasukkan "false, true" di bagian akhir di sini? Saya tidak dapat menemukannya di dokumentasi.
garson
Salah menjawab semua operator posisi $[] 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 dengan arrayFilters Refrence: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters dan docs.mongodb.com/manual/reference/operator/update/…
Lawrence Eagles
0

Perlu diketahui bahwa beberapa jawaban di utas ini menyarankan penggunaan $ [] SALAH.

db.collection.update(
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},
   {multi:true}
)

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]dengan arrayFiltersmenentukan kondisi item array sehingga jawaban Neil Lunn benar.

Wenda Hu
sumber
0

Perbarui bidang array dalam banyak dokumen di mongo db.

Gunakan $ pull atau $ push dengan memperbarui banyak kueri untuk memperbarui elemen array di mongoDb.

Notification.updateMany(
    { "_id": { $in: req.body.notificationIds } },
    {
        $pull: { "receiversId": req.body.userId }
    }, function (err) {
        if (err) {
            res.status(500).json({ "msg": err });
        } else {
            res.status(200).json({
                "msg": "Notification Deleted Successfully."
            });
        }
    });
Irfan
sumber
0

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:

db.collection.update({"events.profile":10}, { $set: { "events.$[elem].handled" : 0 } },
   {
     multi: true,
     arrayFilters: [ { "elem.profile": 10 } ]
})

Kunjungi mongodb doc di sini

Apa yang dilakukan kode:

  1. {"events.profile":10} memfilter koleksi Anda dan mengembalikan dokumen yang cocok dengan filter

  2. The $setpembaruan Operator: memodifikasi pencocokan bidang dokumen itu bekerja pada.

  3. {multi:true}Itu membuat .update()memodifikasi semua dokumen yang cocok dengan filter sehingga berperilaku sepertiupdateMany()

  4. { "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

Lawrence Eagles
sumber