Ce n'est pas possible avec une seule mise à jour atomique, j'ai bien peur que vous deviez effectuer quelques opérations de mise à jour qui satisfont aux deux conditions.
Décomposer la logique de mise à jour en deux opérations de mise à jour distinctes, la première nécessiterait d'utiliser le positionnel $
opérateur
pour identifier l'élément dans l'history
tableau que vous voulez et le $set
pour mettre à jour les champs existants. Cette opération suit la logique mettre à jour les champs SI le nom ET l'organisation correspondent
Maintenant, vous voudriez utiliser le findAndModify()
méthode pour cette opération car elle peut renvoyer le document mis à jour. Par défaut, le document retourné n'inclut pas les modifications apportées à la mise à jour.
Ainsi, armé de cet arsenal, vous pouvez ensuite sonder votre deuxième logique lors de l'opération suivante, c'est-à-dire mettre à jour SI cette combinaison de "history.name" et "history.organisation" n'existe pas dans le tableau . Avec cette deuxième opération de mise à jour, vous devrez ensuite utiliser le $push
opérateur pour ajouter les éléments.
L'exemple suivant illustre le concept ci-dessus. Il suppose initialement que vous disposez de la partie requête et du document à mettre à jour en tant qu'objets distincts.
Prenons par exemple lorsque nous avons des documents qui correspondent au tableau d'historique existant, il ne fera qu'une seule opération de mise à jour, mais si les documents ne correspondent pas, alors le findAndModify()
renverra null, utilisez cette logique dans votre deuxième opération de mise à jour pour envoyer le document au tableau :
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 } }
);
}
Après cette opération pour les documents qui correspondent, l'interrogation de la collection donnera le même
db.users.find({ "email": "[email protected]" });
Sortie :
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "[email protected]",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
}
]
}
Considérez maintenant les documents qui ne correspondent pas :
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 } }
);
}
Interroger cette collection pour ce document
db.users.find({ "email": "[email protected]" });
donnerait
Sortie :
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "[email protected]",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
},
{
"name" : "foo",
"organisation" : "bar"
}
]
}