2011-08-30 12 views
23

Nella documentazione ufficiale di MongoDB accennano upserts, quindi sarebbe davvero bello di scrivere un comando upsert invece di:Upserting in Mongo DB usando ufficiale C# conducente

if (_campaignRepo.Exists(camp)) 
{ 
    _campaignRepo.DeleteByIdAndSystemId(camp); 
} 

_campaignRepo.Save(camp); 

qualcosa che attuare tale logica sulla livello db se è possibile. Allora, qual è il modo di fare un upsert se ce n'è uno?

risposta

25

Il seguente codice è da un app di lavoro:

weekplanStore.Update(
    Query.EQ("weekNumber", week), 
    Update.Replace(rawWeekPlan), 
    UpdateFlags.Upsert); 

Il weekplanStore è la mia collezione MongoDB, e il codice aggiornerà il documento trovato con la query nel primo argomento o inserisci uno nuovo se non ne trova uno. Il "trucco" è usare il modificatore UpdateFlags.Upsert.

Il rawWeekPlan è l'oggetto inserito o aggiornato, e ha il seguente tipo:

private class RawWeekPlan 
{ 
    public ObjectId id; 
    public int weekNumber; 
    public WeekPlanEntry[] entries; 
} 

e trasformato in BSON dal conducente automaticamente.

+0

Funziona per le raccolte nidificate? Hai provato? Perché non funziona per loro nel mio caso –

+0

Non so. Non l'ho provato su collezioni annidate. –

+0

Il problema è in id-s. Ho fatto una domanda su un'altra discussione –

39

Versione 2 del driver MongoDB C# richiede l'impostazione del flag IsUpsert nei comandi di scrittura. Questo esempio invierà un intero documento.

var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } }; 
var result = await collection.ReplaceOneAsync(
    filter: new BsonDocument("_id", 123), 
    options: new UpdateOptions { IsUpsert = true } 
    replacement: newDoc); 

versione 1 del conducente # MongoDB C implementa questa logica all'interno del comando Save.

var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } }; 
collection.Save(newDoc); 

Il metodo Save è una combinazione di inserimento e aggiornamento. Se il membro Id del documento ha un valore, allora si presume che sia un documento esistente e Salva le chiamate Aggiorna sul documento (impostando il flag Upsert nel caso in cui effettivamente sia un nuovo documento dopo tutto). Altrimenti si presume che sia un nuovo documento e Salva chiamate Inserisci dopo aver prima assegnato un nuovo valore univoco al membro Id.

Riferimento: http://mongodb.github.io/mongo-csharp-driver/1.11/driver/#save-tdocument-method

Nota: Questo richiede la corretta mappatura del campo Id comunque. Maggiori informazioni su questo qui: http://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#identifying-the-id-field-or-property

+0

Questo non è più possibile con la nuova API. –

+0

Aggiornato. Anche se penso che la nuova API abbia reso i comandi di upsert più difficili da usare. –

+0

Cosa viene passato al filtro se il nuovo ID di dispositivo di sicurezza è nullo, cioè è un inserto? Solo un documento bson vuoto? – BenCr

5

È possibile utilizzare il comando aggiornamento periodico, ma solo passare il flag di aggiornamento upsert

MongoCollection collection = db.GetCollection("matches"); 
var query = new QueryDocument("recordId", recordId); 

var update = Update.Set("FirstName", "John").Set("LastName","Doe"); 
matchCollection.Update(query, update, UpdateFlags.Upsert, SafeMode.False); 

Tale codice è adattato da un'applicazione di lavoro (abbreviato per chiarezza)

21

partire da V2.0 il driver è una nuova API asincrono. La vecchia API non dovrebbe più essere utilizzata in quanto è una facciata di blocco sulla nuova API ed è deprecata.

Il modo in cui attualmente raccomandato per upsert un documento viene chiamando e in attesa ReplaceOneAsync con la bandiera IsUpsert acceso e un filtro che corrisponde al documento in questione:

Hamster hamster = ... 
var replaceOneResult = await collection.ReplaceOneAsync(
    doc => doc.Id == hamster.Id, 
    hamster, 
    new UpdateOptions {IsUpsert = true}); 

è possibile verificare se l'operazione è stata un inserto o un aggiornamento guardando ReplaceOneResult.MatchedCount:

+0

Sto cercando di usare ReplaceOneAsync ma lancia un'eccezione: "Nome elemento '' non è valido", sto usando il filtro per updateOneasync funziona ma non con replaceone. Potete per favore aiutarmi? –