mongoDB:C#驱动程序V2如何更新嵌套集合中的项

时间:2016-04-23 10:57:41

标签: c# mongodb mongodb-.net-driver

我有以下课程设计:

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

     

反序列化类的Days属性时发生错误   QuoteMyDayServer.ServerLogic.UserDayStore:无法反序列化   来自BsonType'Document'的'List'。

     

bei MongoDB.Driver.Linq.MongoQueryProviderImpl 1.Execute(Expression expression) bei MongoDB.Driver.Linq.MongoQueryProviderImpl 1.Execute [TResult](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()in   C:\发展协会\ APPS \ QuoteMyDay \服务器\ QuoteMyDayServer \ NancyTests \ MongoTests.cs:Zeile   148。   --- EndederStappelüberwachungvomvorhergehenden Ort,dem dieAusnahmeausgelöstwurde--- bei   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)bei   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)bei   Xunit.Sdk.TestInvoker`1&LT;&GT; c__DisplayClass46_1&LT; b__1&GT; d.MoveNext()   在   C:\ BuildAgent \工作\ cb37e9acf085d108的\ src \ xunit.execution \ SDK \框架\运动员\ TestInvoker.cs:Zeile   227。   --- EndederStappelü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 \工作\ cb37e9acf085d108的\ src \ xunit.execution \ SDK \框架\ ExecutionTimer.cs:Zeile   48。   --- EndederStappelüberwachungvomvorhergehenden Ort,dem dieAusnahmeausgelöstwurde--- bei   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)bei   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)bei Xunit.Sdk.ExceptionAggregator.d__9.MoveNext()   在   C:\ BuildAgent \工作\ cb37e9acf085d108的\ src \ xunit.core \ SDK \ ExceptionAggregator.cs:Zeile   90。

     

System.FormatException

     

无法从BsonType'Document'反序列化'List'。

     

贝   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   序列化器,BsonDeserializationContext context)bei   MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext   context,BsonMemberMap memberMap)

如果存在具有相同“DateOfDay”的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"
    }
}

5 个答案:

答案 0 :(得分:2)

我相信你的问题是你的Update语句在一个案例中使用Set而在另一个案例中使用AddToSet。 AddToSet是基于数组的操作,Set直接分配值。您应该在两种情况下都使用AddToSet,以确保MongoDB中存在一个数组。

FormatException是因为我们期待一个数组(因为类型是List),而是我们得到一个文档。

答案 1 :(得分:1)

好吧,我看到几个错误(很可能是拼写错误),所以我给它一个通行证。但是,您的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;
}

答案 2 :(得分:0)

感谢@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对象。

只要我有一个有效的解决方案,我就会更新这个问题

答案 3 :(得分:0)

经过一些尝试和错误后,我想我知道找到了正确的方法:

    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更新数组元素。

答案 4 :(得分:0)

而不是

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/