如何使用 UpdateManyAsync 更新多个文档

How to update many documents using UpdateManyAsync

我有以下方法来更新 MongoDB 中的文档:

public async Task UpdateAsync(T entity)
{
    await _collection.ReplaceOneAsync(filter => filter.Id == entity.Id, entity);
}

哪个工作正常 - 我只是想知道是否有人有 UpdateManyAsync 函数如何工作的示例:

public async Task UpdateManyAsync(IEnumerable<T> entities)
{
    await _collection.UpdateManyAsync(); // What are the parameters here
}

如有任何建议,我们将不胜感激!

UpdateOneAsyncupdate 和 Mongo shell 中的 multi: true 的工作方式相同。所以你可以指定过滤条件和更新操作,它会影响多个文档。例如,要增加所有 a 字段,其中 a 大于 10,您可以使用此方法:

var builder = Builders<SampleClass>.Update;
await myCollection.UpdateManyAsync(x => x.a > 10, builder.Inc(x => x.a, 1));

我猜您想替换多个文档。这可以使用 bulkWrite 方法来实现。如果您需要 C# 中的泛型方法,那么您可以引入某种标记接口来构建替换操作的过滤器部分:

public interface IMongoIdentity
{
    ObjectId Id { get; set; }
}

然后您可以将通用约束添加到您的 class 并在 .NET 中使用 BuikWrite,如下所示:

class YourRepository<T> where T : IMongoIdentity
{
    IMongoCollection<T> collection;

    public async Task UpdateManyAsync(IEnumerable<T> entities)
    {
        var updates = new List<WriteModel<T>>();
        var filterBuilder = Builders<T>.Filter;

        foreach (var doc in entities)
        {
            var filter = filterBuilder.Where(x => x.Id == doc.Id);
            updates.Add(new ReplaceOneModel<T>(filter, doc));
        }

        await collection.BulkWriteAsync(updates);
    }
}

作为@mickl 的回答,你不能使用 x=> x.Id 因为它是一个通用的 使用如下:

public async Task<string> UpdateManyAsync(IEnumerable<T> entities)
{ 
     var updates = new List<WriteModel<T>>();
     var filterBuilder = Builders<T>.Filter;

     foreach (var doc in entities)
     {
          foreach (PropertyInfo prop in typeof(T).GetProperties())
          {
              if (prop.Name == "Id")
              {
                  var filter = filterBuilder.Eq(prop.Name, prop.GetValue(doc));
                  updates.Add(new ReplaceOneModel<T>(filter, doc));
                  break;
              }
          }
     }
     BulkWriteResult result = await _collection.BulkWriteAsync(updates);
     return result.ModifiedCount.ToString();
}

或者你通过 Bson 属性:

public async Task UpdateManyAsync(IEnumerable<TEntity> objs, CancellationToken cancellationToken = default) 
{
var updates = new List<WriteModel<TEntity>>();
var filterBuilder = Builders<TEntity>.Filter;

foreach (var obj in objs)
{
    foreach (var prop in typeof(TEntity).GetProperties())
    {
        object[] attrs = prop.GetCustomAttributes(true);
        foreach (object attr in attrs)
        {
            var bsonId = attr as BsonIdAttribute;
            if (bsonId != null)
            {
                var filter = filterBuilder.Eq(prop.Name, prop.GetValue(obj));
                updates.Add(new ReplaceOneModel<TEntity>(filter, obj));
                break;
            }
        }
    }
}

await _dbCollection.BulkWriteAsync(updates, null, cancellationToken);

}