Operadores de arrays en updates de MongoDB | Nicolás Garzón
Inicio Wiki MongoDB Operadores de arrays en updates Volver a MongoDBMongoDB
Operadores de arrays en updates Explica $push, $addToSet, $pull, $pop, operadores posicionales y arrayFilters para modificar arrays sin reemplazar todo el documento.
Última actualización Actualizada 25 de jul de 2026
MongoDB ofrece operadores especializados para modificar arrays dentro de un documento sin leerlos y reemplazarlos completos. Estos operadores mantienen atomicidad por documento, pero no eliminan los problemas de crecimiento, duplicación, índices multikey o concurrencia sobre un documento hotspot.
Nota anteriorActualizaciones Nota siguiente Upserts Añade un elemento al final:
JavaScript
Copiar db. orders. updateOne (
{ _id : orderId, status : 'draft' } ,
{
$push : {
items : {
productId,
quantity : 2 ,
unitPrice
}
}
}
) ; Puede combinarse con modificadores:
JavaScript
Copiar {
$push : {
recentEvents : {
$each : newEvents,
$position : 0 ,
$sort : { createdAt : - 1 } ,
$slice : 20
}
}
} Este patrón conserva solo veinte eventos recientes. El orden de aplicación conceptual permite insertar, ordenar y recortar dentro de una operación.
Añade el valor solo si no existe uno exactamente igual:
JavaScript
Copiar { $addToSet : { tags : 'coffee' } } JavaScript
Copiar {
$addToSet : {
tags : { $each : [ 'coffee' , 'organic' ] }
}
} No garantiza unicidad por una propiedad interna de un subdocumento. Para membresías únicas, una colección separada con índice unique es más segura.
Elimina todos los elementos que cumplen una condición:
JavaScript
Copiar {
$pull : {
items : { productId }
}
} No elimina únicamente la primera coincidencia. Si los duplicados tienen significado, define una identidad de item y utiliza una condición precisa.
Elimina el primer o último elemento. Es útil para estructuras muy específicas, pero no ofrece semántica de queue distribuida.
Actualiza el primer elemento que coincide con la query:
JavaScript
Copiar db. orders. updateOne (
{
_id : orderId,
'items.productId' : productId
} ,
{
$set : {
'items.$.quantity' : 3
}
}
) ; La condición del array debe aparecer en el filtro. Si existen duplicados, solo el primer elemento coincidente se actualiza.
Aplica la modificación a todos los elementos:
JavaScript
Copiar db. orders. updateOne (
{ _id : orderId } ,
{
$set : {
'items.$[].reviewed' : false
}
}
) ; Puede modificar muchos elementos dentro de un documento. Sigue siendo atómico para ese documento, pero el coste aumenta con el tamaño del array.
Seleccionan elementos según condiciones:
JavaScript
Copiar db. orders. updateOne (
{ _id : orderId, businessId } ,
{
$set : {
'items.$[item].status' : 'cancelled'
}
} ,
{
arrayFilters : [
{
'item.productId' : productId,
'item.status' : 'pending'
}
]
}
) ; Esto actualiza todos los elementos que cumplen el filtro item. Los identificadores deben ser claros y las condiciones deben validar tipos y estados.
Es posible combinar operadores:
JavaScript
Copiar {
$set : {
'sections.$[section].tasks.$[task].done' : true
}
} con filtros separados. Aunque sea posible, una ruta muy profunda puede indicar un document boundary demasiado complejo. Evalúa legibilidad, tamaño, permisos y frecuencia de cambio.
TypeScript
Copiar const order = await orders. findOne ( { _id: orderId } ) ;
order. items. push ( newItem) ;
await orders. replaceOne ( { _id: orderId } , order) ; Otra request puede haber modificado items entre ambas operaciones. $push conserva cambios concurrentes independientes mejor que un reemplazo completo.
Si una orden no permite dos líneas para el mismo producto, $push no protege la regla. Opciones:
filtrar que no exista y usar $push;
utilizar $addToSet si igualdad completa sirve;
modelar items por clave;
mantener colección separada con índice unique;
aceptar duplicados y consolidarlos explícitamente.
JavaScript
Copiar db. orders. updateOne (
{
_id : orderId,
'items.productId' : { $ne : productId }
} ,
{
$push : { items : newItem }
}
) ; es atómica para el documento. Debes revisar el resultado para detectar que ya existía.
Al añadir o quitar elementos, un contador puede actualizarse en la misma operación:
JavaScript
Copiar {
$push : { items : newItem } ,
$inc : { itemCount : 1 }
} Esto mantiene coherencia dentro del documento. Si scripts externos modifican el array sin actualizar el contador, se necesita validation operativa y reconciliación.
Conservar un subset limitado:
JavaScript
Copiar {
$push : {
recentNotifications : {
$each : [ notification] ,
$position : 0 ,
$slice : 50
}
}
} Es apropiado si el array es una cache o subset, no la única copia de datos que deben conservarse. Recortar destruye elementos anteriores.
Cada cambio del array puede modificar entradas de índice. Un update aparentemente pequeño puede implicar trabajo considerable si el array participa en varios índices.
cantidad de elementos;
índices multikey;
compound index restrictions;
frecuencia de updates;
tamaño del documento;
working set.
Los operadores son atómicos, pero las reglas deben estar en el filtro.
Ejemplo: incrementar quantity con límite máximo:
JavaScript
Copiar db. orders. updateOne (
{
_id : orderId,
items : {
$elemMatch : {
productId,
quantity : { $lte : 98 }
}
}
} ,
{
$inc : {
'items.$.quantity' : 2
}
}
) ; El filtro evita superar 100 en condiciones concurrentes, siempre que no existan duplicados ambiguos.
$push puede crear el array si el campo no existe, pero falla si existe con tipo no array.
Debe migrarse o manejarse; no se comporta como array vacío.
El positional operator puede no encontrar posición. Revisa matchedCount y modifiedCount.
$ actualiza el primer match; $[id] puede actualizar varios.
La operación puede superar el límite de 16 MiB.
El documento resultante debe cumplir schema validation.
Solo compara valores dentro de un documento.
Modifica todos los elementos.
La aplicación asume éxito aunque no coincidió el elemento.
Los operadores facilitan crecer, no lo hacen sostenible.
Permiten modificar campos arbitrarios.
Actualiza una coincidencia inesperada.
Prueba array missing, null y vacío.
Introduce duplicados.
Ejecuta updates concurrentes.
Revisa límites y validators.
Mide documento e índice multikey.
Confirma matchedCount y modifiedCount.
Prueba múltiples array filters.
Verifica que $slice no destruya la fuente única.
Audita paths permitidos.
Revisa el modelo si la ruta es demasiado profunda.
Los operadores de arrays permiten cambios atómicos y precisos, pero exigen comprender matching, duplicados, posiciones y crecimiento. $push, $addToSet, $pull, $, $[] y $[id] resuelven problemas diferentes. Ninguno reemplaza un buen document boundary.
Comprueba lo aprendido
¿Qué diferencia existe entre $push y $addToSet?
¿Qué actualiza el operador $?
¿Cuándo utilizarías array filters?
¿Por qué $slice no corrige por sí solo un modelo ilimitado?
¿Cómo evitarías insertar dos veces el mismo productId?
¿Qué costes añade un índice multikey durante updates?