新版 mongodb.driver 必须 await 异步方法,filterdefinition 构造错误、连接未验证、混用 insertoneasync/replaceoneasync、忽略 deletedcount 等是常见致错原因。

别直接抄示例代码——新版 MongoDB.Driver(2.19+)不 await 就根本没执行,用错 InsertOneAsync 和 ReplaceOneAsync 会静默丢字段,查不到数据往往不是条件写错,而是 FilterDefinition 构造方式不对。
连接 MongoClient 必须先验证连通性,不能只 new 出来就开干
驱动不会在构造 MongoClient 时立即连服务器,直到你第一次发请求才真正握手。常见错误是看到 new MongoClient(...) 没报错,就以为连上了,结果后续 InsertOneAsync 直接超时或抛 MongoConnectionException。
- 本地开发:确认
mongod进程在跑(Windows 查服务,macOS/Linux 执行ps aux | grep mongod) - Atlas 连接串必须 URL 编码用户名密码,
@要转成%40,/要转成%2F - 连接串末尾建议加上
?retryWrites=true&w=majority(MongoDB 6+ 默认要求,漏了可能静默失败) - 最可靠验证方式:
await client.ListDatabaseNames().ToListAsync(),比任何 CRUD 都早一步暴露连接问题
InsertOneAsync 和 ReplaceOneAsync 语义完全不同,混用必丢数据
InsertOneAsync 是“插入一条,_id 冲突就报错”;ReplaceOneAsync 是“按条件找一条,整个文档替换成你传的这个对象”。新手常把后者当“更新几个字段”用,结果没传的字段全变 null 或默认值。
- 局部更新字段(比如只改
Name):必须用UpdateOneAsync+Builders<t>.Update.Set()</t> - 整文档替换(且确保 _id 存在):才用
ReplaceOneAsync,否则新文档会带自动生成的_id,旧文档还在 - 插入后要拿生成的 ID:
var result = await collection.InsertOneAsync(doc); var id = result.InsertedId;,别再手动new ObjectId() - 如果传入实体的
Id字段已存在,InsertOneAsync会抛MongoWriteException,不是静默忽略
FilterDefinition 构造错,查询就等于没加条件
Find() 方法只认 FilterDefinition<t></t>,不是 BsonDocument、不是 JSON 字符串、更不是 LINQ 表达式裸写(除非用强类型泛型 + 正确引用)。
- 推荐写法(类型安全、IDE 可提示):
Builders<user>.Filter.Eq(x => x.Status, "active")</user> - 若坚持用字符串解析:
FilterDefinition<user>.Parse("{status: 'active'}")</user>,注意单引号、字段名大小写 - 错例:
collection.Find(new BsonDocument("status", "active"))—— 这个BsonDocument不会被识别为过滤器,等价于查全量 - 按
_id查询时,务必转ObjectId:Builders<user>.Filter.Eq("_id", new ObjectId(id))</user>,传字符串直接匹配失败
DeleteResult.DeletedCount 必须检查,不抛异常 ≠ 删成功
删除操作默认不抛异常(比如条件没匹配到),但 DeleteResult.DeletedCount 是唯一真实反映结果的字段。忽略它,等于把“删了 0 条”当成“删成功”。
- 单条删除后务必验证:
if (result.DeletedCount == 0) throw new InvalidOperationException("未找到匹配文档"); - 批量删除前,建议先
await collection.CountDocumentsAsync(filter)预估数量,避免误删全表 -
DeleteManyAsync没事务回滚,生产环境慎用;如需安全,改用FindAsync+ 分批DeleteOneAsync - 删完记得通知下游或清缓存,否则状态不一致——这不是驱动的问题,但常出现在真实链路里
最易被跳过的点:所有 Async 方法必须 await,且调用方方法得是 async Task;Result 或 Wait() 在 ASP.NET Core 或 WinForms 中极易死锁。还有,IMongoClient 必须全局单例,别每次请求都 new 一个——连接池复用不是可选项,是性能底线。











