簡體   English   中英

mongoDB:C#驅動程序V2如何更新嵌套集合中的項目

[英]mongoDB: C# driver V2 How to update item in a nested collection

我有以下類設計:

public class UserDayStore
{
    public Guid Id { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public DateTime EndOfSubscription { get; set; }
    public bool active { get; internal set; }
    public DateTime LastModified;

    public List<DbDayRecord>  Days { get; set; }
}

public class DbDayRecord
{
    public Guid StoreId { get; set; }
    public DateTime LastModified { get; set; }
    public DateTime DateOfDay { get; set; }

    public String Quote { get; set; }

}

添加UserDayStore可以正常工作,也可以將嵌套項添加到List<Days> 當我嘗試更新DayRecord時,更新已完成,正如我在Robomongo中看到的那樣。 但是當我在UserStore集合中嘗試搜索文檔之后,我得到了這個例外:

System.FormatException

反序列化QuoteMyDayServer.ServerLogic.UserDayStore類的Days屬性時發生錯誤:無法從BsonType“Document”反序列化“List”。

bei MongoDB.Driver.Linq.MongoQueryProviderImpl 1.Execute(Expression expression) bei MongoDB.Driver.Linq.MongoQueryProviderImpl 1.Execute [TResult](Expression expression)bei System.Linq.Queryable.First [TSource](IQueryable 1 source) bei QuoteMyDayServer.ServerLogic.QuoteDatabase.<SetUserState>d__10.MoveNext() in C:\\Entwicklung\\Apps\\QuoteMyDay\\Server\\QuoteMyDayServer\\QuoteMyDayServer\\ServerLogic\\QuoteDatabase.cs:Zeile 147. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Runtime.CompilerServices.TaskAwaiter 1.GetResult()bei NancyTests.MongoTests.d__8.MoveNext()在C:\\ Entwicklung \\ Apps \\ QuoteMyDay \\ Server \\ QuoteMyDayServer \\ NancyTests \\ MongoTests.cs:Zeile 148. --- EndederStapelüberwachungvomvorhergehenden Ort,dem dieAusnahmeausgelöstwurde - - bei Sys tem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任務任務)bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務任務)bei Xunit.Sdk.TestInvoker`1。<> c__DisplayClass46_1。<b__1> d.MoveNext()in C :\\ BuildAgent \\ work \\ cb37e9acf085d108 \\ src \\ xunit.execution \\ Sdk \\ Frameworks \\ Runners \\ TestInvoker.cs:Zeile 227. --- EndederStapelüberwachungvomvorhergehenden Ort,dem dieAusnahmeausgelöstwurde--- bei System.Runtime .CompilerServices.TaskAwaiter.ThrowForNonSuccess(任務任務)bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務任務)bei Xunit.Sdk.ExecutionTimer.d__4.MoveNext()在C:\\ BuildAgent \\ work \\ cb37e9acf085d108 \\ src \\ xunit中。執行\\ Sdk \\ Frameworks \\ ExecutionTimer.cs:Zeile 48. --- EndederStappelüberwachungvomvorhergehenden Ort,dem dieAusnahmeausgelöstwurde--- bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)bei System.Runtime .CompilerServices.TaskAwaiter.HandleNon SuccessAndDebuggerNotification(任務任務)bei Xunit.Sdk.ExceptionAggregator.d__9.MoveNext()在C:\\ BuildAgent \\ work \\ cb37e9acf085d108 \\ src \\ xunit.core \\ Sdk \\ ExceptionAggregator.cs:Zeile 90。

System.FormatException

無法從BsonType“文檔”反序列化“列表”。

bei MongoDB.Bson.Serialization.Serializers.EnumerableSerializerBase 2.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) bei MongoDB.Bson.Serialization.Serializers.SerializerBase 1.MongoDB.Bson.Serialization.IBsonSerializer.Deserialize(BsonDeserializationContext context,BsonDeserializationArgs args)bei MongoDB .Bson.Serialization.IBsonSerializerExtensions.Deserialize(IBsonSerializer serializer,BsonDeserializationContext context)bei MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext context,BsonMemberMap memberMap)

如果存在具有相同“DateOfDay”的DayRecord,則更新DayRecord的方法,否則將插入新的DayRecord。

    public async Task<bool> UpdateDayRecord(Guid storeID, DbDayRecord dayRecord)
    {
        var stores = GetUserStores();

        var builder = Builders<UserDayStore>.Filter;
        var filter = builder.Eq("Id", storeID);
        var result = await stores.FindAsync(filter);

        if (!await result.AnyAsync()) // Check is a Store with that Id exists
        {
            return false;
        }
        dayRecord.StoreId = storeID;

        filter =  builder.ElemMatch("Days", Builders<DbDayRecord>.Filter.Eq("DateOfDay", dayRecord.DateOfDay));
        result = await stores.FindAsync(filter);


        if (await result.AnyAsync())
        {

            var update = Builders<UserDayStore>.Update.Set("Days", dayRecord).CurrentDate("LastModified");

            var updateResult = await stores.UpdateOneAsync(filter, update);

            return (updateResult.ModifiedCount == 1);
        }
        else
        {

            filter = Builders<UserDayStore>.Filter.Eq("Id", storeID);
            var update = Builders<UserDayStore>.Update.AddToSet("Days", dayRecord).CurrentDate("LastModified");

            var updateResult = await stores.UpdateOneAsync(filter, update);

            return (updateResult.ModifiedCount == 1);
        }
    }

在調用該方法並更新現有的DayRecord后,我在嘗試訪問UserDayStore時獲得上述異常:

    public async Task<Guid> GetStoreId (string username)
    { 
        var stores = GetUserStores();

        var filter = Builders<UserDayStore>.Filter.Eq("UserName", username);

        var result = await stores.FindAsync(filter);

        return result.First().Id;
    }

它在FindAsync調用中失敗。

這是更新后JSON文檔的樣子

{
    "_id" : LUUID("e858f1cc-c81d-7244-b8a0-8beec3c8e10d"),
    "LastModified" : ISODate("2016-04-23T10:43:17.293Z"),
    "UserName" : "TestUser",
    "Password" : "4242",
    "EndOfSubscription" : ISODate("2016-06-22T22:00:00.000Z"),
    "active" : true,
    "Days" : {
        "StoreId" : LUUID("e858f1cc-c81d-7244-b8a0-8beec3c8e10d"),
        "LastModified" : ISODate("2016-04-24T00:00:00.000Z"),
        "DateOfDay" : ISODate("2016-04-23T00:00:00.000Z"),
        "Quote" : "Testquote1"
    }
}

我相信你的問題是你的Update語句在一個案例中使用Set而在另一個案例中使用AddToSet。 AddToSet是基於數組的操作,Set直接分配值。 您應該在兩種情況下都使用AddToSet,以確保MongoDB中存在一個數組。

FormatException是因為我們期待一個數組(因為類型是List),而是我們得到一個文檔。

好吧,我看到幾個錯誤(最可能是拼寫錯誤),所以我給它一個通行證。 但是,您的GetStoreId實現有點風險。 如果給定用戶名沒有匹配的商店,該怎么辦? 你假設總會出現一個錯誤的文件。

我已經改變了GetStoreId實現,所以將它與你的交換,看它是否有效。

public async Task<Guid> GetStoreId (string username)
{       
    var cursor = await collection.FindAsync(x => x.UserName == username);

    var userDayStore = await cursor.FirstOrDefaultAsync();

    return userDayStore != null ? userDayStore.Id: Guid.Empty;
}

感謝@Saleem的幫助,我發現了這個問題。

在更新之前,JSON文檔如下所示:

{
    "_id" : LUUID("f7379cb0-bace-0442-9942-4452f8646522"),
    "LastModified" : ISODate("2016-04-23T12:59:31.358Z"),
    "UserName" : "TestUser",
    "Password" : "4242",
    "EndOfSubscription" : ISODate("2016-06-22T22:00:00.000Z"),
    "active" : true,
    "Days" : [ 
        {
            "StoreId" : LUUID("f7379cb0-bace-0442-9942-4452f8646522"),
            "LastModified" : ISODate("2016-04-24T00:00:00.000Z"),
            "DateOfDay" : ISODate("2016-04-23T00:00:00.000Z"),
            "Quote" : "Testquote1"
        }
    ]
}

所以問題在於更新。 它將List更改為DayRecord對象。

只要我有一個有效的解決方案,我就會更新這個問題

經過一些嘗試和錯誤,我想我知道找到了正確的方法:

    filter =  builder.ElemMatch("Days", Builders<DbDayRecord>.Filter.Eq("DateOfDay", dayRecord.DateOfDay));
    result = await stores.FindAsync(filter);

    if (await result.AnyAsync())  // Record already exists, update it
    {

        var update = Builders<UserDayStore>.Update.Set("Days.$", dayRecord).CurrentDate("LastModified");

        var updateResult = await stores.UpdateOneAsync(filter, update);

        return (updateResult.ModifiedCount == 1);
    }
    else // Add new Record to array
    {

        filter = Builders<UserDayStore>.Filter.Eq("Id", storeID);
        var update = Builders<UserDayStore>.Update.AddToSet("Days", dayRecord).CurrentDate("LastModified");

        var updateResult = await stores.UpdateOneAsync(filter, update);

        return (updateResult.ModifiedCount == 1);
    }

重點在於:

    var update = Builders<UserDayStore>.Update.Set("Days.$", dayRecord).CurrentDate("LastModified");

添加.$使mongo更新數組元素。

代替

var update = Builders<UserDayStore>.Update.Set("Days.$", dayRecord).CurrentDate("LastModified");

你也可以這樣做:

var update = Builders<UserDayStore>.Update.Set(x => x.Days[-1], dayRecord).CurrentDate("LastModified");

資料來源: http//www.mattburkedev.com/updating-inside-a-nested-array-with-the-mongodb-positional-operator-in-c-number/

暫無
暫無

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

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