MongoDB C# BulkWrite批量局部更新及Upsert实现问题
核心问题说明
现有代码编译/运行失败的核心原因是Update.Set的字段选择写法错误:x.StockPointStocks.ElementAt(-1)是无效的LINQ调用,索引-1不存在,且MongoDB C#驱动无法将该表达式解析为合法的字段更新路径。
整体采用BulkWriteAsync搭配UpdateOneModel、开启IsUpsert的实现思路是符合需求的,仅需要修正更新定义,补充upsert场景下的字段初始化逻辑即可。
修正方案
你需要直接指定要更新的根字段StockPointStocks,不需要调用ElementAt方法;同时补充SetOnInsert逻辑,避免upsert插入新文档时缺失其他必要字段。
修正后的完整代码如下:
public async Task<IResult<bool>> UpdateStock(List<Product> products) { var bulkOps = products.Select(record => new UpdateOneModel<Product>( // 匹配ProductCode相等的文档,用Eq写法比Where解析效率更高 Builders<Product>.Filter.Eq(x => x.ProductCode, record.ProductCode), Builders<Product>.Update // 全量替换匹配文档的StockPointStocks字段 .Set(x => x.StockPointStocks, record.StockPointStocks) // 仅插入新文档时 .SetOnInsert(x => x.FutureStock, record.FutureStock ?? new List<FutureStock>()) .SetOnInsert(x => x.Id, record.Id) ) { IsUpsert = true }) .Cast<WriteModel<Product>>() .ToList(); // 可选配置:关闭有序执行提升批量操作性能,无需严格按传入顺序执行时可开启 var bulkWriteOptions = new BulkWriteOptions { IsOrdered = false }; await _databaseContext.ProductCollection().BulkWriteAsync(bulkOps, bulkWriteOptions); return await Result<bool>.SuccessAsync(); }
补充说明
Set方法会在文档匹配成功(无论更新还是插入)时,都将对应字段设置为传入值,适合全量替换StockPointStocks的需求。如果后续需要按库存点维度合并数组数据、而非全量覆盖,需要改用$push、$addToSet等数组操作符。SetOnInsert配置的字段仅在upsert触发插入逻辑时生效,更新已存在的文档时不会修改这些字段,不会误覆盖存量数据。- 关闭
IsOrdered后,MongoDB不需要保证操作按传入顺序执行,遇到单个操作失败也不会中断后续操作,批量写入性能会有明显提升。
内容的提问来源于stack exchange,提问作者Houlahan
相关产品推荐
相关产品推荐

