簡體   English   中英

如何在MongoDB C#驅動程序中將元素不存在的情況下更新/插入到文檔的子數組中

[英]How to update/ insert if not exist an element into a sub array of a document in MongoDB C# driver

我有一個包含一個文檔數組(或多或少復雜)的文檔,我想創建1個查詢,該查詢將基於過濾器更新該數組的元素,如果沒有匹配的元素,則將該元素插入到數組中。 我嘗試了幾件事,但沒有任何效果。 我不想做2個請求以避免並發問題。

以下是我的文檔模型,該模型使用自己擁有的汽車為駕駛員建模

public string Driver{ get; set; }
public Cars[] OwnedCars{ get; set; }

讓我們假設我有一個這樣的模型。

汽車可以定義如下:

Car {
    color: string;
    plateNumber: string
    insuranceNumber: string,
    options: object
        .
        .
        .
}

問題是我可以改變汽車的顏色,買一輛新車。

我想要一個能夠根據用戶的車牌號添加或更新文檔的請求。

我嘗試了幾件事:

我創建了一個過濾器,如下所示:輸入了driverId,car和plateNumber

var filter = Builders < CarModel > .Filter.And(
    Builders < ViewConfigCollStorageModel > .Filter.Eq(x = > x.Driver, driverId),
    Builders < ViewConfigCollStorageModel > .Filter.ElemMatch(x = > x.ownedCars, x = > x.insuranceNumber == plateNumber));

更新可能如下所示:

var update = Builders<CarModel>.Update.Set(x => x.ownedCars[-1], car);
var res = await ViewConfigCollection.RawCollection.UpdateOneAsync(filter, update, option);

在選項中我們可以放

var option = new UpdateOptions() { IsUpsert = true};

如果找到汽車,該集合將很好地工作,但是如果汽車不存在,則由於位置運算符而返回錯誤。

我嘗試了AddToSet運算符,但如果某個屬性與顏色不匹配,它將插入一個新對象,而我想更新現有對象。

如果您有任何想法,請不要猶豫。 謝謝哈克

您可以使用如下的bulkwrite命令來做到這一點:

db.StorageModel.bulkWrite([
    {
        updateOne: {
            filter: {
                "DriverID": "321",
                "OwnedCars": {
                    "$not": {
                        "$elemMatch": {
                            "PlateNumber": "ABC123"
                        }
                    }
                }
            },
            update: {
                "$push": {
                    "OwnedCars": {
                        "PlateNumber": "ABC123",
                        "Color": "White"
                    }
                }
            }
        }
    },
    {
        updateOne: {
            filter: {
                "DriverID": "321",
                "OwnedCars": {
                    "$elemMatch": {
                        "PlateNumber": "ABC123"
                    }
                }
            },
            update: {
                "$set": {
                    "OwnedCars.$": {
                        "PlateNumber": "ABC123",
                        "Color": "White"
                    }
                }
            }
        }
    }
])

這是生成上面的mongodb命令的C#代碼。 為了簡潔起見,它使用MongoDB.Entities。

 using MongoDB.Entities; using System.Linq; namespace StackOverflow { public class Program { public class StorageModel : Entity { public string DriverID { get; set; } public Car[] OwnedCars { get; set; } } public class Car { public string PlateNumber { get; set; } public string Color { get; set; } } private static void Main(string[] args) { new DB("test"); (new StorageModel { DriverID = "321", OwnedCars = new[] { new Car { PlateNumber = "ABC123", Color = "Red"} } }).Save(); var updatedCar = new Car { PlateNumber = "ABC123", Color = "White" }; var bulk = DB.Update<StorageModel>(); bulk.Match(s => s.DriverID == "321" && !s.OwnedCars.Any(c => c.PlateNumber == updatedCar.PlateNumber)) .Modify(b => b.Push(s => s.OwnedCars, updatedCar)) .AddToQueue(); bulk.Match(s => s.DriverID == "321" && s.OwnedCars.Any(c => c.PlateNumber == updatedCar.PlateNumber)) .Modify(b => b.Set(s => s.OwnedCars[-1], updatedCar)) .AddToQueue(); bulk.Execute(); } } } 

您好,謝謝您的回答,確實我們現在有1個請求。 但是,兩個請求都被執行。 即使插入發生在之前,也總是調用更新。

具有2個請求的解決方案如下所示:

 var res = await CarCollection.UpdateOneAsync(filterTryInsert, updateTryInsert);
           if(res.UpsertedId == null && res.MatchedCount == 0 && res.ModifiedCount ==0)
             {
              var resUp = await 
              CarCollection.UpdateOneAsync(filterUpdate,updateUp);
              return resUp.ModifiedCount > 0;
             }

在這里,如果用戶不存在汽車,則無法直接插入汽車,upsertedId不會為null,因此不會到達if塊。

與此相關的問題是並發問題,如果同一用戶嘗試在一個瀏覽器中調用一個更新,而在另一個瀏覽器中調用一個刪除,我們最終可能會這樣做:

推送=>刪除=>更新這種情況下的更新將導致錯誤,因為該元素不存在。

單請求解決方案比較安全,因為它可以讓數據庫管理並發避免此類問題。

Ryan解決方案的C#代碼如下所示:

        var bulkOps = new List<WriteModel<CarModel>>() { modelPush, modelUpdate };

        var res = await CarCollection.BulkWriteAsync(bulkOps);
        return res.ModifiedCount > 0;

現在的問題是,批量寫入是否可以始終避免執行兩個請求?

提前致謝:

陳克勤

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM