MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDB:subdocumento upsert


Não, não há realmente uma solução melhor para isso, então talvez com uma explicação.

Suponha que você tenha um documento em vigor que tenha a estrutura mostrada:
{ 
  "name": "foo", 
  "bars": [{ 
       "name": "qux", 
       "somefield": 1 
  }] 
}

Se você fizer uma atualização como esta
db.foo.update(
    { "name": "foo", "bars.name": "qux" },
    { "$set": { "bars.$.somefield": 2 } },
    { "upsert": true }
)

Então está tudo bem porque o documento correspondente foi encontrado. Mas se você alterar o valor de "bars.name":
db.foo.update(
    { "name": "foo", "bars.name": "xyz" },
    { "$set": { "bars.$.somefield": 2 } },
    { "upsert": true }
)

Então você vai ter um fracasso. A única coisa que realmente mudou aqui é que no MongoDB 2.6 e acima o erro é um pouco mais sucinto:
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"
    }
})

Isso é melhor em alguns aspectos, mas você realmente não quer "upsert" de qualquer maneira. O que você quer fazer é adicionar o elemento à matriz onde o "nome" não existe atualmente.

Então, o que você realmente quer é o "resultado" da tentativa de atualização sem o sinalizador "upsert" para ver se algum documento foi afetado:
db.foo.update(
    { "name": "foo", "bars.name": "xyz" },
    { "$set": { "bars.$.somefield": 2 } }
)

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

Então, quando os documentos modificados são 0 então você sabe que deseja emitir a seguinte atualização:
db.foo.update(
    { "name": "foo" },
    { "$push": { "bars": {
        "name": "xyz",
        "somefield": 2
    }}
)

Realmente não há outra maneira de fazer exatamente o que você quer. Como as adições ao array não são estritamente um tipo de operação "conjunto", você não pode usar $addToSet combinado com a funcionalidade de "atualização em massa" lá, para que você possa "desencadear" suas solicitações de atualização.

Nesse caso, parece que você precisa verificar o resultado ou aceitar ler todo o documento e verificar se deseja atualizar ou inserir um novo elemento de matriz no código.