MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

MongoDB:upsert sottodocumento

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.