J'ai un document Mongo qui contient un tableau d'éléments.
Je voudrais réinitialiser l' .handled
attribut 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?
arrays
mongodb
mongodb-query
LiorH
la source
la source
Réponses:
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:
la source
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: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.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».
la source
elem
?arrayFilters
encore en charge , donc exécutez la mise à jour via CLI. stackoverflow.com/questions/48322834/…Ce qui a fonctionné pour moi, c'est ceci:
Je pense que c'est plus clair pour les débutants mongo et tous ceux qui connaissent JQuery et ses amis.
la source
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
et je reçoisOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Je souhaite effectuer cette mise à jour directement à partir d'un shell mongo sans utiliser l'API Javascript.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).
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 ethandled
non é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 correspondentquery
et 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.
la source
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: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"$setDifference
utilisé pour filtrer toutes lesfalse
valeurs renvoyées par l'$map
opé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
: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
$filter
opération qui est plus simple: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: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: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:Quel que soit le cas, il y a certaines choses que vous ne pas voulez faire dans la mise à jour:
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
$set
le 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$set
soit 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.Ne calculez pas les valeurs d'index à mettre à jour: là où cela est similaire à l'approche "one shot", vous calculez simplement cette position
0
et cette position2
(et ainsi de suite) sont les éléments pour mettre à jour et coder ces éléments avec une déclaration éventuelle comme: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.
la source
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:
Cela peut être résumé dans une fonction à l'aide d'un rappel pour le test conditionnel
la source
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:
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 #
la source
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.
J'espère que cela aide quelqu'un comme moi.
la source
J'ai essayé ce qui suit et cela fonctionne bien.
// fonction de rappel en cas de nodejs
la source
Vous pouvez mettre à jour tous les éléments dans MongoDB
Il mettra à jour toute la valeur «status» à «completed» dans le tableau «arr»
Si un seul document
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
la source
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:
la source
L'opérateur $ [] sélectionne tous les tableaux imbriqués. Vous pouvez mettre à jour tous les éléments du tableau avec '$ []'
Référence
la source
$[]
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é avecarrayFilters
Refrence: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters et docs.mongodb.com/manual/reference/operator/update/…Veuillez noter que certaines réponses de ce fil suggérant d'utiliser $ [] sont FAUX.
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]
avecarrayFilters
pour spécifier la condition des éléments du tableau afin que la réponse de Neil Lunn soit correcte.la source
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.
la source
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:
Visitez mongodb doc ici
Ce que fait le code:
{"events.profile":10}
filtre votre collection et renvoie les documents correspondant au filtreL'
$set
opérateur de mise à jour: modifie les champs correspondants des documents sur lesquels il agit.{multi:true}
Il.update()
modifie tous les documents correspondant au filtre et se comporte donc commeupdateMany()
{ "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
la source