【问题标题】:C# MongoDb - How to update one field in nested documents?C# MongoDb - 如何更新嵌套文档中的一个字段?
【发布时间】:2020-06-29 19:02:29
【问题描述】:

我想要实现的是向Finish() 方法提供包含客户ID 和工作InternalIds 的List<JobList>。 然后我想遍历客户端并更新所有与 JobInternalIds 匹配的作业并将当前日期时间设置为 FinishedAt 字段。 问题是我完全不知道如何更新嵌套对象。

我尝试过类似下面的方法,但没有成功。

public class Client
{
    [BsonId]
    public ObjectId Id { get; set;}
    public string Name { get; set;}
    public List<Job> Jobs { get; set;}
}

public class Job
{
    public string InternalId { get; set;}
    public string Name { get; set;}
    public DateTime? FinishedAt { get; set;}
}

public class JobList
{
    public string ClientId { get; set; }
    List<string> JobInternalIds { get; set; }
}

public async Task Finish(List<JobList> joblist)
{   
    var updateDefinition = new UpdateDefinitionBuilder<Client>()
        .Set(x => x.Job[0].FinishedAt, DateTime.UtcNow); // don't know how to set datetime to finishedAt for each elements of collection that matches InternalIds

    foreach(var item in joblist)
    {
        await _db.Collection.UpdateManyAsync(item.ClientId, updateDefinition);
    }   
}

----------EDITED----------
public async Task Finish(List<JobList> joblist)
{
    var updateDefinition = Builders<Client>.Update
        .Set(x => x.Jobs[-1].FinishedAt, DateTime.UtcNow);

    foreach (var item in joblist)
    {
        var internalIds = item.JobInternalIds.Select(x => x.InternalId).ToList();   
        var idFilter = Builders<Client>.Filter.Eq(x => x.Id, item.ClientId);
        var internalIdsFilter = Builders<Client>.Filter.ElemMatch(x => x.Jobs, y => internalIds.Contains(y.InternalId));
        var combinedFilters = Builders<Client>.Filter.And(idFilter, internalIdsFilter);

        await _db.Collection.UpdateManyAsync(combinedFilters, updateDefinition);
    }
}

【问题讨论】:

    标签: c# mongodb mongodb.driver


    【解决方案1】:

    您可以使用过滤后的位置运算符来更新数组中匹配条件的所有元素:

    var internalIds = new[] { "1", "2" };
    var idFilter = Builders<Client>.Filter.Eq(x => x.Id, objectId);
    var updateDefinition = Builders<Client>.Update
        .Set("Jobs.$[job].FinishedAt", DateTime.UtcNow);
    
    await collection.UpdateManyAsync(idFilter, updateDefinition,
         new UpdateOptions
         {
             ArrayFilters = new []
             {
                 new BsonDocumentArrayFilterDefinition<BsonDocument>(new BsonDocument("job.groupName", new BsonDocument("$in", new BsonArray(internalIds)))),
             }
         });
    

    查看这篇博文以获取一些示例 - https://kevsoft.net/2020/03/23/updating-arrays-in-mongodb-with-csharp.html

    【讨论】:

    • 感谢您的回答,是否可以在更新定义中添加附加条件以仅更新 InternalId 等于某物的作业?我只想更新 JobList 中的特定工作。
    • 是的,为此您需要构建一个匹配该条件的过滤器,然后使用位置运算符 ($)。在 C# 中甚至还有一种类型化的方法可以做到这一点。 Builders&lt;Client&gt;.Update.Set( x=&gt; x.Jobs[-1].FinishedAt, DateTime.UtcNow)
    • 嘿凯文,你能告诉我我做错了什么吗?我认为过滤器工作正常,因为它正在更新正确的元素,但它只更新第一个匹配元素而不是全部。因此,如果我有两个匹配的元素,我必须运行 Finish() 方法两次。
    • 啊,明白了,如果您只想更新数组中的某些过滤器,则需要使用数组过滤器 - docs.mongodb.com/manual/reference/operator/update/…
    • 谢谢,它运行良好。我绝对需要增加我对mongo的了解! :)
    猜你喜欢
    • 2021-10-25
    • 2018-12-08
    • 2016-08-04
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 2017-06-05
    • 2022-01-02
    • 1970-01-01
    相关资源
    最近更新 更多