Comment mettre à jour plusieurs éléments de tableau dans mongodb

183

J'ai un document Mongo qui contient un tableau d'éléments.

Je voudrais réinitialiser l' .handledattribut de tous les objets du tableau où .profile= XX.

Le document se présente sous la forme suivante:

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

donc, j'ai essayé ce qui suit:

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

Cependant, il met à jour uniquement le premier élément de tableau correspondant dans chaque document. (C'est le comportement défini pour $ - l'opérateur positionnel .)

Comment puis-je mettre à jour tous les éléments de tableau correspondants?

LiorH
la source
2
La mise à jour d'un sous-ensemble ou de tous les éléments du tableau a été ajoutée à mongodb 3.6: docs.mongodb.com/manual/reference/operator/update/…
Jaap
assurez-vous de vérifier arrayFilters et de déterminer quelle requête utiliser pour rendre la mise à jour efficace. Découvrez la réponse de Neil Lunn: stackoverflow.com/a/46054172/337401
Jaap
vérifier ma réponse
Ucdemir

Réponses:

111

Pour le moment, il n'est pas possible d'utiliser l'opérateur positionnel pour mettre à jour tous les éléments d'un tableau. Voir JIRA http://jira.mongodb.org/browse/SERVER-1243

En guise de solution, vous pouvez:

  • Mettez à jour chaque élément individuellement (événements.0.événements gérés.1.handled ...) ou ...
  • Lisez le document, effectuez les modifications manuellement et enregistrez-le en remplaçant l'ancien (cochez "Mettre à jour si actuel" si vous souhaitez vous assurer des mises à jour atomiques)
Javier Ferrero
la source
15
si vous rencontrez un problème similaire, votez pour ce numéro - jira.mongodb.org/browse/SERVER-1243
LiorH
J'aime vraiment l'approche de lecture et d'enregistrement du document. Mais j'ai utilisé Couch avant Mongo, donc cette approche semble plus naturelle car il n'y a pas d'API de requête pour Couch, juste une API REST pour des documents entiers
adam
1
Ces deux approches nécessitent une quantité de mémoire assez élevée, non? S'il y a beaucoup de documents qui doivent être recherchés, et doivent tous les charger (ou les tableaux imbriqués) afin de les mettre à jour ... + aussi un peu gênant à implémenter si cela doit être fait de manière asynchrone ...
Ixx
13
Toutes difficultés techniques mises à part, il est assez étonnant que cette fonctionnalité ne soit pas disponible dans MongoDB. Cette contrainte enlève beaucoup de liberté à la personnalisation du schéma de base de données.
Sung Cho le
5
Neil Lunn stackoverflow.com/a/46054172/337401 a répondu à cela pour la version 3.6. Puisqu'il s'agit d'une question populaire, il pourrait être utile de mettre à jour cette réponse acceptée avec un renvoi à la réponse par Neil Lunn.
Jaap
74

Avec la sortie de MongoDB 3.6 (et disponible dans la branche de développement de MongoDB 3.5.12), vous pouvez désormais mettre à jour plusieurs éléments de tableau en une seule requête.

Cela utilise la syntaxe d'opérateur de mise à jour positionnelle filtrée$[<identifier>] introduite dans cette version:

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

Le "arrayFilters"tel qu'adopté aux options pour .update()ou même .updateOne(), .updateMany(), .findOneAndUpdate()ou .bulkWrite()méthode précise les conditions pour correspondre à l'identifiant donné dans la déclaration de mise à jour. Tous les éléments qui correspondent à la condition donnée seront mis à jour.

Notant que le "multi"tel qu'indiqué dans le contexte de la question a été utilisé dans l'espoir que cela "mettrait à jour plusieurs éléments", mais ce n'était pas et n'est toujours pas le cas. Son utilisation s'applique ici à "plusieurs documents" comme cela a toujours été le cas ou maintenant spécifié comme paramètre obligatoire .updateMany()dans les versions d'API modernes.

NOTE Un peu ironiquement, puisque ceci est spécifié dans l'argument "options" pour .update()et comme méthodes similaires, la syntaxe est généralement compatible avec toutes les versions récentes des pilotes.

Cependant ce n'est pas le cas du mongoshell, puisque la façon dont la méthode y est implémentée ("ironiquement pour la compatibilité descendante"), l' arrayFiltersargument n'est pas reconnu et supprimé par une méthode interne qui analyse les options afin de fournir une "compatibilité descendante" avec les versions antérieures Versions du serveur MongoDB et .update()syntaxe d'appel d'API «héritée» .

Donc, si vous voulez utiliser la commande dans le mongoshell ou d'autres produits "basés sur le shell" (notamment Robo 3T), vous avez besoin d'une dernière version de la branche de développement ou de la version de production à partir de 3.6 ou plus.

Voir aussi positional all $[]qui met également à jour "plusieurs éléments du tableau" mais sans appliquer aux conditions spécifiées et s'applique à tous les éléments du tableau où c'est l'action souhaitée.

Voir également Mise à jour d'un tableau imbriqué avec MongoDB pour savoir comment ces nouveaux opérateurs positionnels s'appliquent aux structures de tableaux «imbriqués», où «les tableaux sont dans d'autres tableaux».

IMPORTANT - Les installations mises à niveau à partir des versions précédentes "peuvent" ne pas avoir activé les fonctionnalités de MongoDB, ce qui peut également entraîner l'échec des instructions. Vous devez vous assurer que votre procédure de mise à niveau est complète avec des détails tels que les mises à niveau d'index, puis exécutez

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

Ou une version supérieure, selon votre version installée. c'est- "4.0"à- dire pour la version 4 et les suivantes actuellement. Cela a activé des fonctionnalités telles que les nouveaux opérateurs de mise à jour de position et d'autres. Vous pouvez également vérifier avec:

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

Pour revenir au réglage actuel

Neil Lunn
la source
10
La réponse acceptée doit être mise à jour et se référer à cette réponse.
Jaap
3
Qu'est-ce que c'est elem?
user1063287
1
C'est correct. Notez que RoboMongo ne prend pas arrayFiltersencore en charge , donc exécutez la mise à jour via CLI. stackoverflow.com/questions/48322834/…
drlff
merci, Neil, en particulier pour la section IMPORTANT, exactement ce dont j'avais besoin
janfabian
ce code renvoie ERROR dans pymongo. tehre is error: raise TypeError ("% s must be True or False"% (option,)) TypeError: upsert must be True or False
Vagif
67

Ce qui a fonctionné pour moi, c'est ceci:

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

Je pense que c'est plus clair pour les débutants mongo et tous ceux qui connaissent JQuery et ses amis.

Daniel Cerecedo
la source
J'utilise db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...et je reçoisOops.. TypeError: Object # has no method 'forEach'
Squirrl
3
@Squirrl pourrait être une version obsolète de mongodb? Le document explique clairement comment appliquer la fonction forEach à un curseur mais ne précise pas depuis quelle version est prise en charge. docs.mongodb.org/manual/reference/method/cursor.forEach
Daniel Cerecedo
@Squirrl trydb.posts.find(...).toArray().forEach(...)
marmor
Ne pouvons-nous pas faire cela sans utiliser Javascript? Je souhaite effectuer cette mise à jour directement à partir d'un shell mongo sans utiliser l'API Javascript.
Meliodas
1
Pouvez-vous s'il vous plaît écrire cette requête dans le pilote mongodb pour java ou avec spring-data-mongodb? Merci, kris
chiku
18

Cela peut également être accompli avec une boucle while qui vérifie s'il reste des documents contenant encore des sous-documents qui n'ont pas été mis à jour. Cette méthode préserve l'atomicité de vos mises à jour (ce que la plupart des autres solutions ici ne font pas).

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

Le nombre de fois que la boucle est exécutée sera égal au nombre maximal de fois que des sous-documents avec profileégal à 10 et handlednon égal à 0 se produisent dans l'un des documents de votre collection. Donc, si vous avez 100 documents dans votre collection et que l'un d'eux a trois sous-documents qui correspondent queryet que tous les autres documents ont moins de sous-documents correspondants, la boucle s'exécutera trois fois.

Cette méthode évite le risque d'écraser d'autres données qui pourraient être mises à jour par un autre processus pendant l'exécution de ce script. Il minimise également la quantité de données transférées entre le client et le serveur.

Sean
la source
13

Cela est en fait lié au problème de longue date sur http://jira.mongodb.org/browse/SERVER-1243 où il y a en fait un certain nombre de défis à une syntaxe claire qui prend en charge "tous les cas" où les correspondances de plusieurs tableaux sont a trouvé. Il existe en fait des méthodes déjà en place qui «aident» à trouver des solutions à ce problème, telles que les opérations en masse qui ont été mises en œuvre après cet article original.

Il n'est toujours pas possible de mettre à jour plus d'un élément de tableau correspondant dans une seule instruction de mise à jour, donc même avec une mise à jour "multi", tout ce que vous pourrez mettre à jour est juste un élément mathématique dans le tableau pour chaque document de ce seul déclaration.

La meilleure solution possible à l'heure actuelle est de rechercher et de boucler tous les documents correspondants et de traiter les mises à jour groupées qui permettront au moins d'envoyer de nombreuses opérations en une seule demande avec une réponse unique. Vous pouvez éventuellement utiliser .aggregate()pour réduire le contenu du tableau renvoyé dans le résultat de la recherche à ceux qui correspondent aux conditions de la sélection de mise à jour:

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

La .aggregate()partie là fonctionnera quand il y a un identifiant "unique" pour le tableau ou tout le contenu pour chaque élément forme un élément "unique" lui-même. Cela est dû à l'opérateur "set" $setDifferenceutilisé pour filtrer toutes les falsevaleurs renvoyées par l' $mapopération utilisée pour traiter le tableau pour les correspondances.

Si le contenu de votre tableau ne contient pas d'éléments uniques, vous pouvez essayer une autre approche avec $redact:

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

Là où sa limitation est que si "manipulé" était en fait un champ censé être présent à d'autres niveaux de document, vous obtiendrez probablement des résultats non attendus, mais c'est bien là où ce champ n'apparaît qu'à une seule position du document et correspond à l'égalité.

Les futures versions (post 3.1 MongoDB) au moment de l'écriture auront une $filteropération qui est plus simple:

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

Et toutes les versions qui prennent en charge .aggregate()peuvent utiliser l'approche suivante avec $unwind, mais l'utilisation de cet opérateur en fait l'approche la moins efficace en raison de l'expansion de la baie dans le pipeline:

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

Dans tous les cas où la version MongoDB prend en charge un "curseur" à partir de la sortie agrégée, il s'agit simplement de choisir une approche et d'itérer les résultats avec le même bloc de code affiché pour traiter les instructions de mise à jour en bloc. Les opérations en masse et les "curseurs" de la sortie agrégée sont introduits dans la même version (MongoDB 2.6) et travaillent donc généralement main dans la main pour le traitement.

Dans les versions encore plus anciennes, il est probablement préférable d'utiliser simplement .find()pour renvoyer le curseur et de filtrer l'exécution des instructions uniquement au nombre de fois où l'élément du tableau est mis en correspondance pour les .update()itérations:

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

Si vous êtes absolument déterminé à faire des mises à jour «multi» ou que vous estimez que c'est finalement plus efficace que de traiter plusieurs mises à jour pour chaque document correspondant, vous pouvez toujours déterminer le nombre maximum de correspondances de tableaux possibles et simplement exécuter une mise à jour «multi» autant fois, jusqu'à ce qu'il n'y ait plus de documents à mettre à jour.

Une approche valide pour les versions MongoDB 2.4 et 2.2 pourrait également être utilisée .aggregate()pour trouver cette valeur:

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

Quel que soit le cas, il y a certaines choses que vous ne pas voulez faire dans la mise à jour:

  1. Ne mettez pas à jour le tableau "en une seule fois": Où, si vous pensez qu'il serait plus efficace de mettre à jour tout le contenu du tableau dans le code, puis uniquement $setle tableau entier dans chaque document. Cela peut sembler plus rapide à traiter, mais il n'y a aucune garantie que le contenu du tableau n'a pas changé depuis sa lecture et la mise à jour effectuée. Bien qu'il $setsoit toujours un opérateur atomique, il ne mettra à jour le tableau qu'avec ce qu'il «pense» être les données correctes, et il est donc susceptible d'écraser tout changement intervenant entre la lecture et l'écriture.

  2. Ne calculez pas les valeurs d'index à mettre à jour: là où cela est similaire à l'approche "one shot", vous calculez simplement cette position 0et cette position 2(et ainsi de suite) sont les éléments pour mettre à jour et coder ces éléments avec une déclaration éventuelle comme:

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

    Encore une fois, le problème ici est la "présomption" que ces valeurs d'index trouvées lors de la lecture du document sont les mêmes valeurs d'index dans le tableau au moment de la mise à jour. Si de nouveaux éléments sont ajoutés au tableau d'une manière qui modifie l'ordre, ces positions ne sont plus valides et les mauvais éléments sont en fait mis à jour.

Donc, jusqu'à ce qu'il y ait une syntaxe raisonnable déterminée pour permettre le traitement de plusieurs éléments de tableau correspondants dans une seule instruction de mise à jour, l'approche de base consiste à mettre à jour chaque élément de tableau correspondant dans une instruction individuelle (idéalement en masse) ou à déterminer essentiellement les éléments de tableau maximum pour mettre à jour ou continuer à mettre à jour jusqu'à ce qu'aucun résultat modifié ne soit renvoyé. Dans tous les cas, vous devez "toujours" traiter les mises à jour de position$ sur l'élément de tableau correspondant, même si cela ne met à jour qu'un élément par instruction.

Les opérations en masse sont en fait la solution "généralisée" pour traiter toutes les opérations qui se révèlent être des "opérations multiples", et comme il y a plus d'applications pour cela que la simple mise à jour de plusieurs éléments de tableau avec la même valeur, elle a bien sûr été implémentée déjà, et c'est actuellement la meilleure approche pour résoudre ce problème.

Blakes Seven
la source
8

Je suis étonné que cela n'ait toujours pas été abordé à Mongo. Globalement, mongo ne semble pas être génial lorsqu'il s'agit de sous-tableaux. Vous ne pouvez pas compter les sous-tableaux simplement par exemple.

J'ai utilisé la première solution de Javier. Lisez le tableau en événements, puis bouclez et construisez le 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});

Cela peut être résumé dans une fonction à l'aide d'un rappel pour le test conditionnel

lukenofautres
la source
Merci pour cela! Je n'arrive pas à croire que cette fonctionnalité n'est toujours pas prise en charge nativement! Utilisé pour incrémenter chaque élément d'un sous-tableau, pour les autres lisant ... pour mettre à jour chaque élément, supprimez simplement l'instruction if.
Zaheer
9
Ce n'est pas une solution sûre. Si un enregistrement est ajouté pendant que vous exécutez la mise à jour, vous corromprez vos données.
Merc
4

J'ai cherché une solution à cela en utilisant le dernier pilote pour C # 3.6 et voici le correctif que j'ai finalement choisi. La clé ici utilise "$ []" qui, selon MongoDB, est nouveau à partir de la version 3.6. Voir https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] pour plus d'informations.

Voici le code:

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

Pour plus de contexte, consultez mon article original ici: Supprimer l'élément de tableau de TOUS les documents à l'aide du pilote MongoDB C #

C0d3 0n3
la source
4

Le fil est très ancien, mais je suis venu chercher une réponse ici, fournissant ainsi une nouvelle solution.

Avec MongoDB version 3.6+, il est désormais possible d'utiliser l'opérateur positionnel pour mettre à jour tous les éléments d'un tableau. Voir la documentation officielle ici .

La requête suivante fonctionnerait pour la question posée ici. J'ai également vérifié avec le pilote Java-MongoDB et cela fonctionne avec succès.

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

J'espère que cela aide quelqu'un comme moi.

ersnh
la source
1

J'ai essayé ce qui suit et cela fonctionne bien.

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

// fonction de rappel en cas de nodejs

Pranay Saha
la source
Ce code met simplement à jour le premier élément correspondant dans le tableau. Mauvaise réponse.
Hamlett
Cela fonctionne pour la v2.6. Vous êtes peut-être dans une version plus ancienne? Voici sa doc docs.mongodb.com/manual/reference/method/db.collection.update/…
Jialin Zou
1

Vous pouvez mettre à jour tous les éléments dans MongoDB

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

Il mettra à jour toute la valeur «status» à «completed» dans le tableau «arr»

Si un seul document

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

Mais si ce n'est pas le cas et que vous ne voulez pas que tous les documents du tableau soient mis à jour, vous devez parcourir l'élément et l'intérieur du bloc 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
la source
0

En fait, la commande save est uniquement sur l'instance de la classe Document. Cela a beaucoup de méthodes et d'attributs. Vous pouvez donc utiliser la fonction lean () pour réduire la charge de travail. Référez-vous ici. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

Un autre problème avec la fonction de sauvegarde, qui créera des données en conflit avec plusieurs sauvegardes en même temps. Model.Update rendra les données cohérentes. Donc, pour mettre à jour plusieurs éléments dans le tableau du document. Utilisez votre langage de programmation familier et essayez quelque chose comme ça, j'utilise mangouste en cela:

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))
})
user3176403
la source
0

L'opérateur $ [] sélectionne tous les tableaux imbriqués. Vous pouvez mettre à jour tous les éléments du tableau avec '$ []'

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

Référence

Ucdemir
la source
Pouvez-vous expliquer pourquoi vous incluez le "faux, vrai" à la fin ici? Je ne le trouve pas dans la documentation.
garson le
Mauvaise réponse, l'opérateur positionnel $[] met à jour uniquement tous les champs du tableau spécifié. Ce qui fonctionne, c'est l'opérateur positionnel filtré qui opère $[identifier]sur les champs de tableau qui correspondent aux conditions spécifiées. Doit être utilisé avec arrayFilters Refrence: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters et docs.mongodb.com/manual/reference/operator/update/…
Lawrence Eagles
0

Veuillez noter que certaines réponses de ce fil suggérant d'utiliser $ [] sont FAUX.

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

Le code ci-dessus mettra à jour «manipulé» à 0 pour tous les éléments du tableau «événements», quelle que soit sa valeur «profil». La requête {"events.profile":10}sert uniquement à filtrer l'ensemble du document, pas les documents du tableau. Dans cette situation, il est indispensable de l'utiliser $[elem]avec arrayFilterspour spécifier la condition des éléments du tableau afin que la réponse de Neil Lunn soit correcte.

Wenda Hu
la source
0

Mettre à jour le champ de tableau dans plusieurs documents dans mongo db.

Utilisez $ pull ou $ push avec update many query pour mettre à jour les éléments du tableau dans 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
la source
0

Premièrement: votre code n'a pas fonctionné car vous utilisiez l'opérateur positionnel $qui identifie uniquement un élément à mettre à jour dans un tableau mais ne spécifie même pas explicitement sa position dans le tableau.

Ce dont vous avez besoin est l'opérateur positionnel filtré $[<identifier>]. Cela mettrait à jour tous les éléments qui correspondent à une condition de filtre de tableau.

Solution:

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

Visitez mongodb doc ici

Ce que fait le code:

  1. {"events.profile":10} filtre votre collection et renvoie les documents correspondant au filtre

  2. L' $setopérateur de mise à jour: modifie les champs correspondants des documents sur lesquels il agit.

  3. {multi:true}Il .update()modifie tous les documents correspondant au filtre et se comporte donc commeupdateMany()

  4. { "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ] Cette technique implique l'utilisation du tableau positionnel filtré avec arrayFilters. le tableau positionnel filtré $[elem]agit ici comme un espace réservé pour tous les éléments des champs de tableau qui correspondent aux conditions spécifiées dans le filtre de tableau.

Filtres matriciels

Lawrence Eagles
la source