2017-09-17 2 views
1

Ich habe eine MongoDB, wo ich Einträge mit Arrays von SubItems aufzeichnen kann. Beim Hinzufügen oder Aktualisieren von SubItems, zuerst Find die Haupt Item, dann füge ich die neue SubItem in das Array SubItems und ersetzen Sie die gesamte Item. Dies funktionierte "großartig", bis ich mit dem Batch-Einfügen begann SubItems.Filialdokument in MongoDB sicher einfügen oder aktualisieren

Ich denke, mein Problem ist, dass die Suche und Aktualisierung sind keine atomare Operation und das Ergebnis ist, dass ich SubItems verlieren.

ich das .NET MongoDB.Driver bin mit und meine speichern Methode sieht wie folgt aus:

public Task Save(string itemId, SubItem subItem) 
{ 
    var itemFilter = Builders<Item>.Filter.Eq(v => v.Id, itemId); 
    var collection = _db.GetCollection<Item>("Items"); 

    var item = await collection.Find(itemFilter).SingleOrDefaultAsync(); 

    item.SubItems.Add(subItem); 
    collection.ReplaceOneAsync(itemFilter, item, new UpdateOptions() { IsUpsert = true }).Wait(); 
    return Task.FromResult(0); 
} 

Hier ist meine Datenmodell:

public class Item 
{ 
    public string Id { get; set; } 
    public List<SubItem> SubItems { get; set; } 
} 

public class SubItem 
{ 
    public string Id { get; set; } 
} 

Gibt es eine Möglichkeit oder Update einfügen a SubItem in einem Vorgang, damit ich sicherstellen kann, dass ich das gesamte Item Dokument konsistent halte, auch wenn ich mehrere Prozesse habe, die versuchen, das Dokument zur gleichen Zeit zu aktualisieren?

+0

"Upserts" und Arrays neigen im Allgemeinen nicht dazu, sich sehr gut zu mischen. Der typische Fall besteht darin, mit mehreren Operationen (typischerweise in großen Mengen) auf das Vorhandensein des Elements im Array zu "testen" und dann entweder das neue Element "zu schieben" oder dort zu "aktualisieren". Sie können den Fall mit "$ addToSet" (https://docs.mongodb.com/manual/reference/operator/update/addToSet/) "etwas vereinfachen" "wenn" der Array-Inhalt einfach Werte oder ein "single" ist " Eigentum. Wenn es jedoch mehr als eine Eigenschaft gibt, bedeutet "Eindeutigkeit" die Kombination dieser Eigenschaften in diesem Kontext, und stattdessen wird auf die "Test" -Ansatz zurückgegriffen. –

+0

Das "upsert" -Problem ist, wenn ein solches Update das Vorhandensein eines Elements in einem Array "testet", "jedes" negative Ergebnis bedeutet, dass ein "upsert" immer dann auftritt, wenn Ihre tatsächliche Absicht darin bestand, das Array von "anzufügen" das vorhandene Dokument und nicht ein neues Dokument. Der tatsächliche Prozess, den Sie anwenden, hängt von Ihrem beabsichtigten Muster ab. Wenn Sie wirklich "upsert" wollen und mehrere Eigenschaften im Array haben wollen, dann meinen Sie eigentlich "mehrere Operationen". –

Antwort

1

Haben Sie sich die AddToSet Methode angeschaut, wenn Sie diese in Kombination mit der Update-Funktion anstelle der ersetzen verwenden, sollten Sie eine bessere Kontrolle über Ihre Atomarität behalten.

var updateBuilder = Builders<Item>.Update.AddToSet(items => items.SubItems, new SubItem()); 

collection.UpdateOne(itemFilter, updateBuilder); 

Wie in Ihrem Fall.

public Task Save(string itemId, SubItem subItem) 
    { 
     var itemFilter = Builders<Item>.Filter.Eq(v => v.Id, itemId); 
     var collection = _db.GetCollection<Item>("Items"); 

     var updateBuilder = Builders<Item>.Update.AddToSet(items => items.SubItems, subItem); 

     collection.UpdateOneAsync(itemFilter, updateBuilder, new UpdateOptions() { IsUpsert = true }).Wait(); 
    } 
Verwandte Themen