Tengo un documento Mongo que contiene una gran variedad de elementos.
Me gustaría restablecer el .handled
atributo de todos los objetos en la matriz donde .profile
= XX.
El documento tiene la siguiente forma:
{
"_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": "....."
}
...
]
}
Entonces, probé lo siguiente:
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
Sin embargo, solo actualiza el primer elemento de matriz coincidente en cada documento. (Ese es el comportamiento definido para $: el operador posicional ).
¿Cómo puedo actualizar todos los elementos de matriz coincidentes?
arrays
mongodb
mongodb-query
LiorH
fuente
fuente
Respuestas:
En este momento no es posible utilizar el operador posicional para actualizar todos los elementos de una matriz. Ver JIRA http://jira.mongodb.org/browse/SERVER-1243
Como solución, puede:
fuente
Con el lanzamiento de MongoDB 3.6 (y disponible en la rama de desarrollo de MongoDB 3.5.12) ahora puede actualizar múltiples elementos de matriz en una sola solicitud.
Esto utiliza la sintaxis de operador de actualización posicional filtrada
$[<identifier>]
introducida en esta versión:El
"arrayFilters"
que pasó a las opciones para.update()
o incluso.updateOne()
,.updateMany()
,.findOneAndUpdate()
o.bulkWrite()
método especifica las condiciones que coinciden con el identificador dado en la instrucción de actualización. Cualquier elemento que coincida con la condición dada será actualizado.Observando que la información
"multi"
dada en el contexto de la pregunta se usó con la expectativa de que esto "actualizaría múltiples elementos", pero este no fue y sigue siendo el caso. Su uso aquí se aplica a "documentos múltiples" como siempre ha sido el caso o ahora se ha especificado como la configuración obligatoria.updateMany()
en las versiones modernas de API.Vea también
positional all $[]
qué también actualiza "elementos de matriz múltiple" pero sin aplicar a condiciones específicas y se aplica a todos los elementos en la matriz donde esa es la acción deseada.Consulte también Actualización de una matriz anidada con MongoDB para ver cómo estos nuevos operadores posicionales se aplican a estructuras de matriz "anidadas", donde las "matrices están dentro de otras matrices".
fuente
elem
?arrayFilters
, por lo que ejecuta la actualización a través de CLI. stackoverflow.com/questions/48322834/…Lo que funcionó para mí fue esto:
Creo que es más claro para los novatos de Mongo y para cualquiera que esté familiarizado con JQuery y sus amigos.
fuente
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
yOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Quiero realizar esta actualización directamente desde un shell mongo sin usar la API de Javascript.Esto también se puede lograr con un ciclo while que verifica si quedan documentos que aún tengan subdocumentos que no se hayan actualizado. Este método conserva la atomicidad de sus actualizaciones (que muchas de las otras soluciones aquí no tienen).
El número de veces que se ejecuta el bucle será igual al número máximo de veces que se produzcan subdocumentos con
profile
10 yhandled
no 0 en ninguno de los documentos de su colección. Entonces, si tiene 100 documentos en su colección y uno de ellos tiene tres subdocumentos que coincidenquery
y todos los demás documentos tienen menos subdocumentos coincidentes, el bucle se ejecutará tres veces.Este método evita el peligro de bloquear otros datos que pueden ser actualizados por otro proceso mientras se ejecuta este script. También minimiza la cantidad de datos que se transfieren entre el cliente y el servidor.
fuente
De hecho, esto se relaciona con el problema de larga data en http://jira.mongodb.org/browse/SERVER-1243, donde de hecho hay una serie de desafíos para una sintaxis clara que admita "todos los casos" donde las coincidencias de matrices múltiples encontró. De hecho, ya existen métodos que "ayudan" en la solución de este problema, como las operaciones masivas que se han implementado después de esta publicación original.
Todavía no es posible actualizar más de un único elemento de matriz coincidente en una sola declaración de actualización, por lo que incluso con una actualización "múltiple", todo lo que podrá actualizar es un solo elemento coincidente en la matriz para cada documento en ese único declaración.
La mejor solución posible en este momento es encontrar y hacer un bucle de todos los documentos coincidentes y procesar actualizaciones masivas que permitirán al menos enviar muchas operaciones en una sola solicitud con una respuesta singular. Opcionalmente, puede usar
.aggregate()
para reducir el contenido de la matriz devuelto en el resultado de la búsqueda a aquellos que coinciden con las condiciones para la selección de actualización:La
.aggregate()
porción allí funcionará cuando haya un identificador "único" para la matriz o todo el contenido para cada elemento forme un elemento "único". Esto se debe a que el operador "set" se$setDifference
utiliza para filtrar losfalse
valores devueltos por la$map
operación utilizada para procesar la matriz en busca de coincidencias.Si su contenido de matriz no tiene elementos únicos, puede probar un enfoque alternativo con
$redact
:Donde está la limitación es que si "manejado" era de hecho un campo destinado a estar presente en otros niveles de documentos, entonces es probable que obtenga resultados inesperados, pero está bien donde ese campo aparece solo en una posición del documento y es una coincidencia de igualdad.
Las versiones futuras (posteriores a MongoDB 3.1) a partir de la escritura tendrán una
$filter
operación más simple:Y todas las versiones que admiten
.aggregate()
pueden usar el siguiente enfoque$unwind
, pero el uso de ese operador lo convierte en el enfoque menos eficiente debido a la expansión de la matriz en la tubería:En todos los casos en que la versión de MongoDB admite un "cursor" de la salida agregada, entonces esto es solo una cuestión de elegir un enfoque e iterar los resultados con el mismo bloque de código que se muestra para procesar las declaraciones de actualización masiva. Las operaciones masivas y los "cursores" de la salida agregada se introducen en la misma versión (MongoDB 2.6) y, por lo tanto, generalmente funcionan de la mano para el procesamiento.
Incluso en versiones anteriores, entonces probablemente sea mejor usar solo
.find()
para devolver el cursor y filtrar la ejecución de las declaraciones solo la cantidad de veces que el elemento de matriz coincide para las.update()
iteraciones:Si está decidido a realizar actualizaciones "múltiples" o considera que en última instancia es más eficiente que procesar múltiples actualizaciones para cada documento coincidente, entonces siempre puede determinar el número máximo de posibles coincidencias de matriz y simplemente ejecutar una actualización "múltiple". veces, hasta que básicamente no hay más documentos para actualizar.
Un enfoque válido para las versiones MongoDB 2.4 y 2.2 también podría usarse
.aggregate()
para encontrar este valor:Cualquiera sea el caso, hay ciertas cosas que no desea hacer dentro de la actualización:
No actualice "una sola vez" la matriz: donde si cree que podría ser más eficiente actualizar todo el contenido de la matriz en código y luego solo
$set
la matriz completa en cada documento. Esto puede parecer más rápido de procesar, pero no hay garantía de que el contenido de la matriz no haya cambiado desde que se leyó y se realizó la actualización. Aunque$set
todavía es un operador atómico, solo actualizará la matriz con lo que "cree" que son los datos correctos y, por lo tanto, es probable que sobrescriba cualquier cambio que ocurra entre lectura y escritura.No calcule los valores de índice para actualizar: cuando sea similar al enfoque de "un disparo", simplemente calcule que la posición
0
y la posición2
(y así sucesivamente) son los elementos para actualizar y codificar esto con una declaración eventual como:Nuevamente, el problema aquí es la "presunción" de que los valores de índice encontrados cuando se leyó el documento son los mismos valores de índice en la matriz al momento de la actualización. Si se agregan nuevos elementos a la matriz de una manera que cambia el orden, esas posiciones ya no son válidas y, de hecho, los elementos incorrectos se actualizan.
Entonces, hasta que haya una sintaxis razonable determinada para permitir que se procesen múltiples elementos de matriz coincidentes en una sola declaración de actualización, entonces el enfoque básico es actualizar cada elemento de matriz coincidente en una declaración individual (idealmente en Bulk) o esencialmente resolver los elementos de matriz máximos para actualizar o seguir actualizando hasta que no se devuelvan más resultados modificados. En cualquier caso, debería "siempre" estar procesando actualizaciones posicionales
$
en el elemento de matriz coincidente, incluso si eso solo está actualizando un elemento por declaración.Las operaciones masivas son, de hecho, la solución "generalizada" para procesar cualquier operación que resulte ser "operaciones múltiples", y dado que hay más aplicaciones para esto que la simple actualización de elementos de matriz múltiple con el mismo valor, por supuesto, se ha implementado ya, y actualmente es el mejor enfoque para resolver este problema.
fuente
Me sorprende que esto todavía no se haya abordado en mongo. En general, mongo no parece ser genial cuando se trata de sub-matrices. No puede contar sub-matrices simplemente por ejemplo.
Usé la primera solución de Javier. Lea la matriz en eventos, luego repita y cree el conjunto exp:
Esto puede resumirse en una función utilizando una devolución de llamada para la prueba condicional
fuente
He estado buscando una solución para esto usando el controlador más nuevo para C # 3.6 y aquí está la solución que finalmente decidí. La clave aquí es usar "$ []", que según MongoDB es nuevo a partir de la versión 3.6. Ver https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] para más información.
Aquí está el código:
Para obtener más contexto, vea mi publicación original aquí: elimine el elemento de matriz de TODOS los documentos usando el controlador MongoDB C #
fuente
El hilo es muy antiguo, pero vine buscando una respuesta aquí, por lo tanto, proporcioné una nueva solución.
Con MongoDB versión 3.6+, ahora es posible usar el operador posicional para actualizar todos los elementos en una matriz. Ver documentación oficial aquí .
La siguiente consulta funcionaría para la pregunta que se hace aquí. También he verificado con el controlador Java-MongoDB y funciona correctamente.
Espero que esto ayude a alguien como yo.
fuente
Intenté lo siguiente y está funcionando bien.
// función de devolución de llamada en caso de nodejs
fuente
Puede actualizar todos los elementos en MongoDB
Actualizará todo el valor de "estado" a "completado" en la matriz "arr"
Si solo un documento
Pero si no es uno y tampoco desea que se actualicen todos los documentos de la matriz, debe recorrer el elemento y dentro del bloque if
fuente
En realidad, el comando guardar es solo en la instancia de la clase Document. Que tienen muchos métodos y atributos. Entonces puede usar la función lean () para reducir la carga de trabajo. Consulte aquí https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
Otro problema con la función de guardar, que hará que los datos de conflicto se guarden con múltiples guardados al mismo tiempo. Model.Update hará que los datos sean consistentes. Entonces, para actualizar varios elementos en una matriz de documentos. Usa tu lenguaje de programación familiar y prueba algo como esto, uso mangosta en eso:
fuente
El operador $ [] selecciona toda la matriz anidada. Puede actualizar todos los elementos de la matriz con '$ []'
Referencia
fuente
$[]
solo actualiza todos los campos en la matriz especificada. Lo que funciona es el operador posicional filtrado$[identifier]
que los operadores en campos de matriz que coinciden con las condiciones especificadas. Debe usarse conarrayFilters
referencia: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters y docs.mongodb.com/manual/reference/operator/update/…Tenga en cuenta que algunas respuestas en este hilo sugieren que el uso $ [] es INCORRECTO.
El código anterior actualizará "manejado" a 0 para todos los elementos en la matriz de "eventos", independientemente de su valor de "perfil". La consulta
{"events.profile":10}
es solo para filtrar todo el documento, no los documentos en la matriz. En esta situación, es una necesidad para utilizar$[elem]
conarrayFilters
especificar la condición de elementos de matriz por lo que la respuesta de Neil Lunn es correcta.fuente
Actualice el campo de matriz en varios documentos en mongo db.
Use $ pull o $ push con la actualización de muchas consultas para actualizar los elementos de la matriz en mongoDb.
fuente
Primero: su código no funcionó porque estaba usando el operador posicional
$
que solo identifica un elemento para actualizar en una matriz pero ni siquiera especifica explícitamente su posición en la matriz.Lo que necesita es el operador posicional filtrado
$[<identifier>]
. Actualizaría todos los elementos que coincidan con una condición de filtro de matriz.Solución:
Visita mongodb doc aquí
Lo que hace el código:
{"events.profile":10}
filtra su colección y devuelve los documentos que coinciden con el filtroEl
$set
operador de actualización: modifica los campos coincidentes de los documentos sobre los que actúa.{multi:true}
Hace que.update()
modifica todos los documentos que coincidan con el filtro por lo tanto, comportándose comoupdateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
Esta técnica implica el uso de la matriz posicional filtrada con arrayFilters. la matriz posicional filtrada aquí$[elem]
actúa como un marcador de posición para todos los elementos en los campos de la matriz que coinciden con las condiciones especificadas en el filtro de matriz.Filtros de matriz
fuente