Receio que não seja possível com uma única atualização atômica, você teria que fazer algumas operações de atualização que satisfaçam as duas condições.
Divida a lógica de atualização em duas operações de atualização distintas, a primeira exigiria o uso do posicional
$
operador
para identificar o elemento no history
array desejado e o $set
para atualizar os campos existentes. Esta operação segue a lógica atualizar campos SE o nome E a organização corresponderem Agora, você deve usar o
findAndModify()
para esta operação, pois pode retornar o documento atualizado. Por padrão, o documento devolvido não inclui as modificações feitas na atualização. Então, armado com esse arsenal, você pode testar sua segunda lógica na próxima operação, ou seja, atualizar SE essa combinação de "history.name" e "history.organization" não existir no array . Com esta operação de segunda atualização, você precisaria usar o
$push
operador para adicionar os elementos. O exemplo a seguir demonstra o conceito acima. Ele inicialmente assume que você tem a parte de consulta e o documento a ser atualizado como objetos separados.
Por exemplo, quando temos documentos que correspondem ao array de histórico existente, ele fará apenas uma única operação de atualização, mas se os documentos não corresponderem, o
findAndModify()
retornará null, use esta lógica em sua segunda operação de atualização para enviar o documento para a 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 } }
);
}
Após esta operação para documentos que correspondam, consultar a coleção produzirá o mesmo
db.users.find({ "email": "[email protected]" });
Saída:
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "[email protected]",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
}
]
}
Agora considere os documentos que não correspondem:
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 coleção para este documento
db.users.find({ "email": "[email protected]" });
renderia
Saída:
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "[email protected]",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
},
{
"name" : "foo",
"organisation" : "bar"
}
]
}