Me temo que no es posible con una sola actualización atómica, tendría que hacer un par de operaciones de actualización que satisfagan ambas condiciones.
Divida la lógica de actualización en dos operaciones de actualización distintas, la primera requeriría el uso de posicional $
operador
para identificar el elemento en el history
matriz que desea y el $set
para actualizar los campos existentes. Esta operación sigue la lógica actualizar campos SI el nombre Y la organización coinciden
Ahora, le gustaría usar el findAndModify()
para esta operación ya que puede devolver el documento actualizado. Por defecto, el documento devuelto no incluye las modificaciones realizadas en la actualización.
Entonces, armado con este arsenal, puede probar su segunda lógica en la siguiente operación, es decir, actualizar SI esa combinación de "historia.nombre" e "historia.organización" no existe en la matriz . Con esta segunda operación de actualización, deberá usar $push
operador para agregar los elementos.
El siguiente ejemplo demuestra el concepto anterior. Inicialmente se supone que tiene la parte de la consulta y el documento que se va a actualizar como objetos separados.
Tomemos, por ejemplo, cuando tenemos documentos que coinciden con la matriz de historial existente, solo realizará una única operación de actualización, pero si los documentos no coinciden, entonces findAndModify()
devolverá un valor nulo, use esta lógica en su segunda operación de actualización para enviar el documento a la matriz:
var doc = {
"name": "Test123",
"organisation": "Rat"
}, // document to update. Note: the doc here matches the existing array
query = { "email": "[email protected]" }; // query document
query["history.name"] = doc.name; // create the update query
query["history.organisation"] = doc.organisation;
var update = db.users.findAndModify({
"query": query,
"update": {
"$set": {
"history.$.name": doc.name,
"history.$.organisation": doc.organisation
}
}
}); // return the document modified, if there's no matched document update = null
if (!update) {
db.users.update(
{ "email": query.email },
{ "$push": { "history": doc } }
);
}
Después de esta operación para los documentos que coinciden, la consulta de la colección arrojará el mismo
db.users.find({ "email": "[email protected]" });
Salida:
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "[email protected]",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
}
]
}
Ahora considere los documentos que no coincidirán:
var doc = {
"name": "foo",
"organisation": "bar"
}, // document to update. Note: the doc here does not matches the current array
query = { "email": "[email protected]" }; // query document
query["history.name"] = doc.name; // create the update query
query["history.organisation"] = doc.organisation;
var update = db.users.findAndModify({
"query": query,
"update": {
"$set": {
"history.$.name": doc.name,
"history.$.organisation": doc.organisation
}
}
}); // return the document modified, if there's no matched document update = null
if (!update) {
db.users.update(
{ "email": query.email },
{ "$push": { "history": doc } }
);
}
Consultando esta colección para este documento
db.users.find({ "email": "[email protected]" });
rendiría
Salida:
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "[email protected]",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
},
{
"name" : "foo",
"organisation" : "bar"
}
]
}