InsertOne、UpdateOne、Find、DeleteOne是MongoDB日常操作核心方法,但需严格匹配驱动版本(如2.10+必须用InsertOneAsync)、正确构造FilterDefinition、校验DeleteResult.DeletedCount、使用Builders进行局部更新而非整文档替换。

InsertOne、UpdateOne、Find、DeleteOne 这四个方法覆盖了 95% 的日常操作,但直接套用示例代码常因版本差异或类型误用导致 NullReferenceException 或 InvalidOperationException —— 根本原因不是语法错,而是驱动版本升级后 BsonDocument 构造逻辑和异步支持方式变了。
用 InsertOneAsync 而不是 Insert,否则会阻塞线程
旧版驱动(如 1.x)允许同步插入:collection.Insert(doc);新版(2.10+)已移除该方法,只保留异步入口。若强行用同步包装(比如 .Result),在 ASP.NET Core 中极易引发死锁。
- 必须用
await collection.InsertOneAsync(doc),且所在方法需标记async Task -
doc可以是BsonDocument,也可以是强类型实体(如new User { Name = "Alice" }),驱动自动序列化 - 插入后想获取生成的
_id,别再手动 newObjectId():用result.InsertedId拿返回值
Find 查询时过滤器写法不匹配,查不到数据却无报错
Find 方法接受 FilterDefinition<T>,不是随便传个 BsonDocument 就行。常见错误是把 JSON 字符串或裸 BsonDocument 直接塞进去,结果过滤器被忽略,返回全量数据(或空)。
- 正确写法:
collection.Find(Builders<User>.Filter.Eq(u => u.Status, "active")) - 复合条件用
&连接:Builders<User>.Filter.Eq(...). & Builders<User>.Filter.Gt(...) - 如果坚持用
BsonDocument,必须转成FilterDefinition:collection.Find(new BsonDocument("status", "active"))是错的;应写collection.Find(FilterDefinition<User>.Parse("{status: 'active'}"))
DeleteOne 和 DeleteMany 的返回值容易被忽略
删除操作不抛异常 ≠ 成功删了文档。驱动返回 DeleteResult,其中 DeletedCount 才是真实删除数量 —— 常见陷阱是只检查是否抛异常,却没验证 result.DeletedCount > 0。
- 按 ID 删除时,务必确认传入的是
ObjectId类型,不是字符串:new ObjectId(id);否则过滤器匹配失败,DeletedCount恒为 0 - 批量删除慎用
DeleteMany:没有事务回滚,删错无法撤回;生产环境建议先CountDocuments预估数量 - 删除后不刷新缓存或通知下游服务,会导致状态不一致 —— 这不是驱动问题,但常出现在实操链路里
更新操作必须显式指定字段,$set 不是默认行为
UpdateOne 默认是“替换整个文档”,不是“局部更新”。如果传一个不带 _id 的实体进去,原 _id 会被丢弃,MongoDB 自动生成新 _id,旧文档还在。
- 局部更新必须用
Builders<User>.Update.Set(u => u.Name, "Bob") - 一次更新多个字段:
Builders<User>.Update.Set(...).Set(...).Set(...) - 想清空某个字段?用
Unset:Builders<User>.Update.Unset(u => u.AvatarUrl) - 更新前没加过滤条件(比如漏写
Eq(u => u.Id, id)),可能误改全表
真正难的不是写对某一行代码,而是每个操作背后隐含的语义约束:插入是否要校验唯一索引、查询是否用了未建索引的字段、更新是否触发了 TTL 或变更流 —— 这些不会在编译时报错,但上线后立刻暴露。



















