MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDB :upsert sous-document

Non, il n'y a pas vraiment de meilleure solution à cela, alors peut-être avec une explication.

Supposons que vous ayez un document en place qui a la structure comme vous le montrez :

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

Si vous faites une mise à jour comme celle-ci

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

Alors tout va bien car le document correspondant a été trouvé. Mais si vous changez la valeur de "bars.name":

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

Ensuite, vous obtiendrez un échec. La seule chose qui a vraiment changé ici est que dans MongoDB 2.6 et supérieur, l'erreur est un peu plus succincte :

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"
    }
})

C'est mieux à certains égards, mais vous ne voulez vraiment pas "upsert" de toute façon. Ce que vous voulez faire est d'ajouter l'élément au tableau où le "nom" n'existe pas actuellement.

Donc, ce que vous voulez vraiment, c'est le "résultat" de la tentative de mise à jour sans l'indicateur "upsert" pour voir si des documents ont été affectés :

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

Cédant en réponse :

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

Ainsi lorsque les documents modifiés sont 0 alors vous savez que vous voulez publier la mise à jour suivante :

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

Il n'y a vraiment pas d'autre moyen de faire exactement ce que vous voulez. Comme les ajouts au tableau ne sont pas strictement une opération de type "set", vous ne pouvez pas utiliser $addToSet combiné avec la fonctionnalité de "mise à jour en masse", afin que vous puissiez "cascader" vos demandes de mise à jour.

Dans ce cas, il semble que vous deviez vérifier le résultat ou accepter de lire l'intégralité du document et de vérifier s'il faut mettre à jour ou insérer un nouvel élément de tableau dans le code.