sql >> Base de Datos >  >> NoSQL >> MongoDB

mongodb $addToSet a un campo que no es de matriz cuando se actualiza en upsert

Lo que intenta hacer aquí es agregar un nuevo elemento a una matriz solo donde el elemento no existe y también crear un nuevo documento donde no existe. Eliges $addToSet porque desea que los artículos sean únicos, pero en realidad desea que sean únicos solo por "a".

Entonces $addToset no hará eso, y más bien necesita "probar" el elemento que está presente. Pero el verdadero problema aquí es que no es posible hacer eso y "upsert" al mismo tiempo. La lógica no puede funcionar ya que se creará un nuevo documento cada vez que no se encuentre el elemento de la matriz, en lugar de agregarlo al elemento de la matriz como desea.

Los errores de operación actuales por diseño como $addToSet no se puede usar para "crear" una matriz, sino solo para "agregar" miembros a una matriz existente. Pero como ya se dijo, tiene otros problemas para lograr la lógica.

Lo que necesita aquí es una secuencia de operaciones de actualización en las que cada una "intenta" realizar la acción esperada. Esto solo se puede hacer con varias declaraciones:

// attempt "upsert" where document does not exist
// do not alter the document if this is an update
db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 2 }] }},
    { "upsert": true }
)

// $push the element where "a": 1 does not exist
db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 2 } }}
)

// $set the element where "a": 1 does exist
db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 2 } }
)

En una primera iteración, la primera declaración "alterará" el documento y creará la matriz con elementos. La segunda declaración no coincidirá con el documento porque el elemento "a" tiene el valor que se especificó. La tercera declaración coincidirá con el documento pero no lo alterará en una operación de escritura porque los valores no han cambiado.

Si ahora cambia la entrada a "b": 3 obtienes respuestas diferentes pero el resultado deseado:

db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 3 }] }},
    { "upsert": true }
)

db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 3 } }}
)

db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 3 } }
)

Así que ahora la primera declaración coincide con un documento con "name": "abc" pero no hace nada ya que las únicas operaciones válidas son sobre "insertar". La segunda declaración no coincide porque "a" coincide con la condición. La tercera declaración coincide con el valor de "a" y cambia "b" en el elemento coincidente al valor deseado.

Posteriormente, cambiar "a" a otro valor que no existe en la matriz permite que tanto 1 como 3 no hagan nada, pero la segunda declaración agrega otro miembro a la matriz manteniendo el contenido único por sus claves "a".

Además, enviar una declaración sin cambios de los datos existentes, por supuesto, dará como resultado una respuesta que dice que nada ha cambiado en todas las cuentas.

Así es como haces tus operaciones. Puede hacer esto con "pedido" Bulk operaciones para que solo haya una única solicitud y respuesta del servidor con la respuesta válida a modificado o creado.