Mongodb'da Birden Çok Dizi Öğesini Güncelleme


183

Öğeleri bir dizi tutan bir Mongo belgesi var.

= XX .handleddizideki tüm nesnelerin özniteliğini sıfırlamak istiyorum .profile.

Belge şu biçimde:

{
    "_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": "....."
        }
        ...
    ]
}

bu yüzden aşağıdakileri denedim:

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

Ancak , her belgede yalnızca ilk eşleşen dizi öğesini güncelleştirir . ( $ İçin tanımlı davranış budur - konumsal işleç .)

Eşleşen tüm dizi öğelerini nasıl güncelleyebilirim ?


2
Bir alt kümeyi veya tüm dizi öğelerini güncelleme mongodb 3.6'ya eklendi: docs.mongodb.com/manual/reference/operator/update/…
Jaap

arrayFilters'ı kontrol ettiğinizden emin olun ve güncellemeyi verimli hale getirmek için hangi sorguyu kullanacağınızı düşünün. Neil Lunn'ın cevabına bir göz atın: stackoverflow.com/a/46054172/337401
Jaap

cevabımı kontrol et
Ucdemir

Yanıtlar:


111

Şu anda, bir dizideki tüm öğeleri güncellemek için konum operatörünü kullanmak mümkün değildir. Bkz. JIRA http://jira.mongodb.org/browse/SERVER-1243

Etrafında bir çalışma olarak şunları yapabilirsiniz:

  • Her öğeyi ayrı ayrı güncelleyin (events.0.handled events.1.handled ...) veya ...
  • Belgeyi okuyun, düzenlemeleri manuel olarak yapın ve eskisini değiştirerek kaydedin ( atomik güncellemeler sağlamak istiyorsanız " Güncelse Güncelle" yi işaretleyin)

15
benzer bir sorununuz varsa, bu konuya oy verin - jira.mongodb.org/browse/SERVER-1243
LiorH

Aslında okuma belgesini ve kaydetme yaklaşımını seviyorum. Ama Couch'u Mongo'dan önce kullandım, böylece Couch için sorgu API'sı olmadığından, tüm belgeler için sadece bir REST api olduğundan yaklaşım daha doğal görünüyor
adam

1
Bu yaklaşımların her ikisi de oldukça yüksek miktarda bellek gerektirir, değil mi? Aranması gereken çok sayıda belge varsa ve güncellemek için tümünü (veya iç içe dizileri) yüklemek zorundaysa ... + bu da eşzamansız olarak yapılması gerekiyorsa uygulanması biraz zahmetli ...
Ixx

13
Tüm teknik zorluklar bir yana, bu özelliğin MongoDB'de mevcut olmaması şaşırtıcıdır. Bu kısıt, veritabanı şemasını özelleştirme özgürlüğünü ortadan kaldırır.
Sung Cho

5
Neil Lunn stackoverflow.com/a/46054172/337401 3.6 sürümü için bunu yanıtladı. Bu popüler bir soru olduğundan, kabul edilen bu cevabı Neil Lunn'in cevabına bir referansla güncellemek zaman alabilir.
Jaap

74

İle MongoDB 3.6 sürümü (MongoDB 3.5.12 den geliştirme dalında ve mevcut) şimdi tek isteği birden dizi elemanlarını güncelleyebilirsiniz.

Bu, bu sürümde sunulan filtrelenmiş konum$[<identifier>] güncelleştirme operatörü sözdizimini kullanır :

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

"arrayFilters"İçin seçeneklere geçti .update()hatta .updateOne(), .updateMany(), .findOneAndUpdate()veya .bulkWrite()yöntem koşulları belirlemektedir güncelleme açıklamada verilen Tanımlayıcıyı eşleşecek. Verilen koşulla eşleşen öğeler güncellenecektir.

"multi"Sorunun bağlamında verilen değerin, bunun "birden çok öğeyi güncelleyeceği" beklentisiyle kullanıldığına dikkat çekti, ancak durum böyle değildi ve hala böyle değil. Burada kullanımı , her zaman olduğu gibi veya şimdi modern API sürümlerinde zorunlu ayar olarak belirtilen "birden çok belge" için geçerlidir .updateMany().

NOT Biraz ironik bir şekilde, bu .update()ve benzeri yöntemler için "seçenekler" argümanında belirtildiği için , sözdizimi genellikle tüm yeni sürüm sürücü sürümleriyle uyumludur.

Bununla birlikte mongo, bu yöntem kabuk için geçerli değildir , çünkü yöntemin orada uygulanma şekli ("ironik olarak geriye dönük uyumluluk için") arrayFiltersargüman tanınmaz ve önceden "geriye dönük uyumluluk" sağlamak için seçenekleri ayrıştıran dahili bir yöntem tarafından kaldırılmaz. MongoDB sunucu sürümleri ve "eski" .update()API çağrısı sözdizimi.

Komutu mongokabukta veya diğer "kabuk tabanlı" ürünlerde (özellikle Robo 3T) kullanmak istiyorsanız, 3.6 veya daha sonraki sürümlerde geliştirme dalından veya üretim sürümünden en son sürüme ihtiyacınız vardır.

Ayrıca positional all $[], belirli koşullara uygulamadan ve istenen eylemin gerçekleştiği dizideki tüm öğeler için geçerli olan "çoklu dizi öğelerini" de güncelleyen bilgilere de bakın .

Ayrıca, bu yeni konum işleçlerinin "dizilerin diğer diziler dahilinde olduğu" "iç içe" dizi yapılarına nasıl uygulandığını öğrenmek için Yuvalanmış Diziyi MongoDB ile Güncelleme konusuna bakın .

ÖNEMLİ - Önceki sürümlerden "" "yükseltilmiş kurulumlar, MongoDB özelliklerini etkinleştirmemiş olabilir ve bu da ifadelerin başarısız olmasına neden olabilir. Yükseltme prosedürünüzün dizin yükseltmeleri gibi ayrıntılarla tamamlandığından emin olmalı ve ardından çalıştırmalısınız.

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

Veya kurulu sürümünüz için geçerli olan daha yüksek bir sürüm. yani "4.0"sürüm 4 ve sonrası için. Bu, yeni konum güncelleştirme işleçleri ve diğerleri gibi özellikleri etkinleştirdi. Şunları da kontrol edebilirsiniz:

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

Geçerli ayara geri dönmek için


10
Kabul edilen cevap güncellenmeli ve bu cevaba bakınız.
Jaap

3
Nedir elem?
user1063287

1
Doğru. RoboMongo'nun arrayFiltershenüz desteklemediğini , bu nedenle CLI üzerinden güncelleme çalıştırıldığını unutmayın. stackoverflow.com/questions/48322834/…
drlff

teşekkürler, Neil, özellikle ÖNEMLİ bölümü için, tam olarak ihtiyacım olan şey
janfabian

bu kod pymongo'da ERROR döndürür. tehre hata: yükseltmek TypeError ("% s Doğru veya Yanlış olmalı"% (seçenek,)) TypeError: upsert Doğru veya Yanlış olmalı
Vagif

67

Benim için işe yarayan şuydu:

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);
  });

Ben mongo yeni başlayanlar ve JQuery & arkadaşları aşina herkes için daha net olduğunu düşünüyorum.


Ben kullanıyorum db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...ve ben alıyorumOops.. TypeError: Object # has no method 'forEach'
Squirrl

3
@Squirrl modası geçmiş mongodb sürümü olabilir mi? Doc, imleçte forEach işlevinin nasıl uygulanacağı konusunda açıktır, ancak hangi sürümün desteklendiğinden bu yana belirtmez. Hercs
Daniel Cerecedo

@Squirrl trydb.posts.find(...).toArray().forEach(...)
marmor

Bunu kullanmadan yapamaz mıyız Javascript? Bu güncelleştirmeyi Javascript API'sini kullanmadan doğrudan bir mongo kabuğundan gerçekleştirmek istiyorum.
Meliodas

1
Bu sorguyu java için mongodb sürücüsüne veya spring-data-mongodb ile yazabilir misiniz? Teşekkürler, kris
chiku

18

Bu ayrıca, henüz güncellenmemiş alt belgeleri olan herhangi bir belgenin kalıp kalmadığını kontrol eden bir while döngüsü ile de gerçekleştirilebilir. Bu yöntem, güncellemelerinizin atomisitesini korur (buradaki diğer çözümlerin çoğunda yoktur).

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 }
    );
}

Döngünün yürütme sayısı, koleksiyonunuzdaki belgelerin hiçbirinde 0'a eşit olmayan profileve 10'a handledeşit olmayan alt belgelerin maksimum sayısına eşit olacaktır . Dolayısıyla, koleksiyonunuzda 100 doküman varsa ve bunlardan birinde eşleşen üç alt querydoküman varsa ve diğer tüm dokümanlarda eşleşen daha az alt doküman varsa, döngü üç kez yürütülür.

Bu yöntem, bu komut dosyası yürütülürken başka bir işlem tarafından güncelleştirilebilecek diğer verilerin gizlenmesi tehlikesini önler. Ayrıca, istemci ve sunucu arasında aktarılan veri miktarını da en aza indirir.


13

Bu aslında, http://jira.mongodb.org/browse/SERVER-1243 adresindeki uzun süredir devam eden sorunla ilgilidir. Burada, çoklu dizi eşleşmelerinin olduğu "tüm durumlar" ı destekleyen açık bir sözdiziminde bir takım zorluklar vardır. bulundu. Aslında, bu sorunun orijinal çözümlerinden sonra uygulanan Toplu İşlemler gibi, bu soruna yönelik çözümlere "yardımcı" olan yöntemler mevcuttur .

Tek bir güncelleme deyiminde tek bir eşleşen dizi öğesinden daha fazlasını güncellemek hala mümkün değildir, bu nedenle "çoklu" bir güncellemeyle bile güncelleyebileceğiniz tek şey, bu tek belgedeki her belge için dizideki yalnızca tek bir matematik öğesidir Beyan.

Şu anda mümkün olan en iyi çözüm, eşleşen tüm belgeleri bulmak ve döngüye sokmak ve en azından birçok işlemin tek bir yanıtla tek bir istekle gönderilmesine izin verecek Toplu güncellemeleri işlemektir. İsteğe bağlı .aggregate()olarak, arama sonucunda döndürülen dizi içeriğini yalnızca güncelleme seçimiyle eşleşen koşullara azaltmak için kullanabilirsiniz :

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();

.aggregate()Dizi ya da her bir elemanı için tüm içerik için bir "eşsiz" tanımlayıcı "benzersiz" bir elemanının kendisi meydana olduğunda kısmı vardır çalışacaktır. Bunun nedeni , diziyi eşleşmeler için işlemek için kullanılan işlemden döndürülen $setDifferencetüm falsedeğerleri filtrelemek amacıyla kullanılan "set" operatörünün olmasıdır $map.

Dizi içeriğinizin benzersiz öğeleri yoksa aşağıdakilerle alternatif bir yaklaşım deneyebilirsiniz $redact:

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

Sınırlaması burada "ele" gerçekten başka bir belge düzeyinde bir alan olması gerekiyorsa, o zaman muhtemelen beklenmedik sonuçlar elde edeceksiniz, ancak bu alanın sadece tek bir belge konumunda göründüğü ve eşitlik eşleşmesi olduğu durumlarda sorun yoktur.

Yazılı olarak gelecekteki sürümler (Post MongoDB sonrası) $filterdaha basit bir işlem yapacak :

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

Ve destek olan tüm sürümler .aggregate()aşağıdaki yaklaşımı kullanabilir $unwind, ancak bu operatörün kullanımı, boru hattındaki dizi genişlemesi nedeniyle onu en az verimli yaklaşım yapar:

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

MongoDB sürümünün toplu çıktıdan bir "imleci" desteklediği tüm durumlarda, bu sadece bir yaklaşım seçme ve sonuçları Toplu güncelleme deyimlerini işlemek için gösterilen aynı kod bloğuyla yineleme meselesidir. Toplu Çıktıdan Toplu İşlemler ve "imleçler" aynı sürümde tanıtılır (MongoDB 2.6) ve bu nedenle genellikle işleme için el ele çalışırlar.

Daha eski sürümlerde bile .find(), imleci döndürmek ve ifadelerin yürütülmesini dizi öğesinin .update()yineleme için kaç kez eşleştiğini filtrelemek için kullanmak en iyisidir :

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 }});
    });
});

Kesinlikle "çoklu" güncellemeler yapmaya kararlıysanız veya eşleşen her belge için birden fazla güncellemeyi işlemekten daha verimli olduğunu düşünüyorsanız, her zaman olası dizi eşleşmelerinin maksimum sayısını belirleyebilir ve yalnızca bu "çoklu" güncellemeyi yürütebilirsiniz. güncellenecek başka belge kalmayıncaya kadar.

MongoDB 2.4 ve 2.2 sürümleri için geçerli bir yaklaşım da .aggregate()bu değeri bulmak için kullanılabilir :

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

Durum ne olursa olsun, sen do bazı şeyler vardır değil güncelleme dahilinde yapmak istiyorum:

  1. Diziyi "tek adımda" güncellemeyin: Burada, koddaki tüm dizi içeriğini ve ardından $sether belgedeki tüm diziyi güncellemenin daha verimli olabileceğini düşünüyorsanız . Bu işlemek daha hızlı görünebilir, ancak dizi içeriğinin okunduğundan ve güncelleme yapıldığından beri değişmediğine dair bir garanti yoktur. $setHala bir atom operatörü olmasına rağmen , diziyi sadece "doğru" veri olduğunu düşündüğü şeyle güncelleyecektir ve bu nedenle okuma ve yazma arasında meydana gelen değişikliklerin üzerine yazması muhtemeldir.

  2. Güncellenecek endeks değerlerini hesaplamayın: "Tek çekim" yaklaşımına benzer şekilde, sadece bu pozisyonu 0ve pozisyonu 2(vb.) Güncelleyecek ve kodlayacak öğelerdir ve aşağıdaki gibi bir deyim vardır:

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

    Yine buradaki sorun, belge okunduğunda bulunan bu indeks değerlerinin güncelleme sırasındaki dizideki aynı indeks değerleri olduğu "varsayımıdır". Diziye siparişi değiştirecek şekilde yeni öğeler eklenirse, bu konumlar artık geçerli olmaz ve yanlış öğeler aslında güncellenir.

Bu nedenle, birden çok eşleşen dizi öğesinin tek güncelleme deyiminde işlenmesine izin vermek için belirlenen makul bir sözdizimi olana kadar, temel yaklaşım, eşleşen her dizi öğesini tek tek bir deyimde (ideal olarak Toplu olarak) güncellemek veya esasen maksimum dizi öğelerini çalışmaktır. değiştirilen sonuç döndürülmeyene kadar güncelleme veya güncellemeye devam etmek için Her durumda, her ifade için yalnızca bir öğe güncelleniyor olsa bile, eşleşen dizi öğesindeki konum$ güncellemelerini "her zaman" işlemelisiniz.

Toplu İşlemler aslında "çoklu işlem" olarak çalışan herhangi bir işlemi işlemek için "genelleştirilmiş" çözümdür ve bunun için sadece aynı değerde birden fazla dizi elemanını güncellemekten daha fazla uygulama olduğundan, elbette uygulanmıştır. ve bu sorunu çözmek için şu anda en iyi yaklaşım.


8

Bu hala mongo'da ele alınmamış olmasına şaşırdım. Alt dizilerle uğraşırken genel mongo harika görünmüyor. Örneğin alt dizileri sayamazsınız.

Javier'in ilk çözümünü kullandım. Diziyi olaylara okuyun ve ardından döngüyü oluşturun ve set exp'yi oluşturun:

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});

Bu, koşullu test için geri arama kullanılarak bir işleve dönüştürülebilir


Bunun için teşekkürler! Bu özelliğin hala yerel olarak desteklenmediğine inanamıyorum! Bunu, bir alt dizinin her öğesini artırmak için, diğerlerinin okuduğu ... her öğeyi güncellemek için if ifadesini kaldırın.
Zaheer

9
Bu güvenli bir çözüm değil. Güncelleştirmeyi çalıştırırken bir kayıt eklenirse verilerinizi bozarsınız.
Merc

4

C # 3.6 için en yeni sürücüyü kullanarak buna bir çözüm arıyordum ve sonunda çözdüğüm düzeltme burada. Buradaki anahtar , MongoDB'ye göre 3.6 sürümünden itibaren yeni olan "$ []" kullanmaktır . Bkz. Https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] için.

İşte kod:

{
   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});
}

Daha fazla bağlam için buraya benim orijinal yazı bakın: MongoDB C # sürücüsü kullanarak TÜM belgelerden dizi öğesini kaldır


4

Konu çok eski, ama ben burada cevap aramaya geldi ve bu nedenle yeni bir çözüm sağladı.

MongoDB sürüm 3.6+ ile artık bir dizideki tüm öğeleri güncellemek için konum operatörünü kullanmak mümkündür. Buradaki resmi belgelere bakın .

Burada sorulan soru için aşağıdaki sorgu işe yarayacaktır. Ayrıca Java-MongoDB sürücüsü ile doğruladım ve başarıyla çalışıyor.

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

Umarım bu benim gibi birine yardımcı olur.



1

MongoDB'deki tüm öğeleri güncelleyebilirsiniz

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

Tüm "durum" değerini "dizi" Dizisinde "tamamlandı" olarak güncelleyecektir

Yalnızca bir belge

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

Ancak biri değilse ve dizideki tüm belgelerin güncellenmesini istemiyorsanız, öğenin içinde ve if bloğunun içinde döngü yapmanız gerekir

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

0

Aslında, save komutu yalnızca Document sınıfının örneğidir. Bunun birçok yöntemi ve özelliği var. Böylece iş yükünü azaltmak için lean () işlevini kullanabilirsiniz. Buraya bakın. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

Kaydetme işleviyle ilgili bir başka sorun, aynı anda çoklu kaydetme ile çakışma verilerini oluşturacaktır. Model.Pdate verileri tutarlı bir şekilde oluşturacaktır. Böylece belge dizisindeki çoklu öğeleri güncellemek için. Bildiğiniz programlama dilini kullanın ve böyle bir şey deneyin, bende mongoose kullanıyorum:

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

0

$ [] operatörü tüm iç içe dizileri seçer. Tüm dizi öğelerini '$ []' ile güncelleyebilirsiniz

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

Referans


Buraya "yanlış, doğru" kelimesini neden eklediğinizi açıklayabilir misiniz? Belgelerde bulamıyorum.
garson

Yanlış konum tüm konum operatörü $[] sadece belirtilen dizideki tüm alanları günceller. İşe $[identifier]yarayan, dizi alanlarındaki işleçlerin belirtilen koşullarla eşleşen filtrelenmiş konum operatörüdür . Refrence ile kullanılmalıdır arrayFilters : docs.mongodb.com/manual/release-notes/3.6/#arrayfilters ve docs.mongodb.com/manual/reference/operator/update/…
Lawrence Eagles

0

Lütfen bu konudaki $ [] kullanımını öneren bazı yanıtların YANLIŞ olduğunu unutmayın.

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

Yukarıdaki kod, "profile" değerine bakılmaksızın "events" dizisindeki tüm öğeler için "handled" i 0 olarak güncelleyecektir. Sorgu {"events.profile":10}dizideki belgeleri değil tüm belgeyi filtrelemektir. Bu durumda kullanmak için bir zorunluluktur $[elem]ile arrayFiltersNeil Lunn'ın cevabın doğru yani dizi öğelerinin durumunu belirtmek için.


0

Mongo db'de birden çok belgede dizi alanını güncelleyin.

MongoDb'deki dizi öğelerini güncellemek için birçok sorguyu güncelle ile $ pull veya $ push kullanın.

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."
            });
        }
    });

0

İlk olarak: konum operatörünü kullandığınız için kodunuz çalışmadı $ sadece bir dizide güncellenecek bir öğeyi tanımlayan ancak dizideki konumunu açıkça belirtmeyen kullandınız.

İhtiyacınız olan şey filtrelenmiş konum operatörüdür $[<identifier>]. Bir dizi filtresi koşuluyla eşleşen tüm öğeleri güncelleştirir.

Çözüm:

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

Mongodb doc'yi ziyaret edin

Kod ne yapar:

  1. {"events.profile":10} koleksiyonunuzu filtreler ve filtreyle eşleşen dokümanları iade eder

  2. $setGüncelleştirme operatörü: değiştirir belgelerin alanlarını eşleşen o üzerinde işlem yapar.

  3. {multi:true}Bu yapar .update()değiştiren dolayısıyla filtreyle eşleşen gibi davrandığını tüm belgeleriupdateMany()

  4. { "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ] Bu teknik, filtre uygulanmış konum dizisinin arrayFilters ile kullanımını içerir. burada filtrelenen konumsal dizi $[elem], dizi alanlarındaki dizi filtresinde belirtilen koşullarla eşleşen tüm öğeler için yer tutucu görevi görür.

Dizi filtreleri

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.