No, non c'è davvero una soluzione migliore a questo, quindi forse con una spiegazione.
Supponiamo di avere un documento in atto con la struttura che mostri:
{
"name": "foo",
"bars": [{
"name": "qux",
"somefield": 1
}]
}
Se esegui un aggiornamento come questo
db.foo.update(
{ "name": "foo", "bars.name": "qux" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Allora tutto va bene perché è stato trovato il documento corrispondente. Ma se modifichi il valore di "bars.name":
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Allora otterrai un fallimento. L'unica cosa che è veramente cambiata qui è che in MongoDB 2.6 e versioni successive l'errore è un po' più conciso:
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"
}
})
In un certo senso è meglio, ma in realtà non vuoi "ribaltarlo" comunque. Quello che vuoi fare è aggiungere l'elemento all'array in cui il "nome" non esiste attualmente.
Quindi quello che vuoi veramente è il "risultato" del tentativo di aggiornamento senza il flag "upsert" per vedere se alcuni documenti sono stati interessati:
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } }
)
Cedendo in risposta:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
Quindi, quando i documenti modificati sono 0
allora sai di voler emettere il seguente aggiornamento:
db.foo.update(
{ "name": "foo" },
{ "$push": { "bars": {
"name": "xyz",
"somefield": 2
}}
)
Non c'è davvero altro modo per fare esattamente quello che vuoi. Poiché le aggiunte all'array non sono strettamente un tipo di operazione "set", non puoi usare $addToSet
combinato con la funzionalità di "aggiornamento in blocco", in modo da poter "unire a cascata" le tue richieste di aggiornamento.
In questo caso sembra che tu debba controllare il risultato, oppure accettare di leggere l'intero documento e verificare se aggiornare o inserire un nuovo elemento dell'array nel codice.