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

MongoDB:upsert subdocumento

No, no hay realmente una mejor solución para esto, así que tal vez con una explicación.

Suponga que tiene un documento que tiene la estructura que muestra:

{ 
  "name": "foo", 
  "bars": [{ 
       "name": "qux", 
       "somefield": 1 
  }] 
}

Si haces una actualización como esta

db.foo.update(
    { "name": "foo", "bars.name": "qux" },
    { "$set": { "bars.$.somefield": 2 } },
    { "upsert": true }
)

Entonces todo está bien porque se encontró un documento coincidente. Pero si cambias el valor de "bars.name":

db.foo.update(
    { "name": "foo", "bars.name": "xyz" },
    { "$set": { "bars.$.somefield": 2 } },
    { "upsert": true }
)

Entonces obtendrá un fracaso. Lo único que realmente ha cambiado aquí es que en MongoDB 2.6 y versiones posteriores, el error es un poco más breve:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 16836,
        "errmsg" : "The positional operator did not find the match needed from the query. Unexpanded update: bars.$.somefield"
    }
})

Eso es mejor en algunos aspectos, pero de todos modos no querrás "perturbarte". Lo que quiere hacer es agregar el elemento a la matriz donde el "nombre" no existe actualmente.

Entonces, lo que realmente quiere es el "resultado" del intento de actualización sin el indicador "upsert" para ver si algún documento se vio afectado:

db.foo.update(
    { "name": "foo", "bars.name": "xyz" },
    { "$set": { "bars.$.somefield": 2 } }
)

Cediendo en respuesta:

WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })

Entonces, cuando los documentos modificados son 0 entonces sabrá que desea emitir la siguiente actualización:

db.foo.update(
    { "name": "foo" },
    { "$push": { "bars": {
        "name": "xyz",
        "somefield": 2
    }}
)

Realmente no hay otra manera de hacer exactamente lo que quieres. Como las adiciones a la matriz no son estrictamente un tipo de operación de "conjunto", no puede usar $addToSet combinado con la funcionalidad de "actualización masiva" allí, para que pueda "en cascada" sus solicitudes de actualización.

En este caso, parece que necesita verificar el resultado o, de lo contrario, aceptar leer el documento completo y verificar si actualizar o insertar un nuevo elemento de matriz en el código.