文档版本: 2.0
最后更新: 2025-01-02
适用版本: monSQLize v1.x
- 📋 概述
- 🎯 当前支持的驱动版本
- ✅ monSQLize 自动处理的差异
- 🛡️ monSQLize 的兼容性保证
- 🚀 未来驱动升级指南
- 📊 测试策略
- 🔧 开发者指南
- 📖 相关资源
- ❓ FAQ
- 📝 更新日志
本文档说明 monSQLize 如何处理 MongoDB Node.js 驱动的版本差异,以及如何确保未来驱动升级时的兼容性。
✅ 重要更新: monSQLize 现已完全支持 MongoDB Driver 4.x, 5.x, 6.x,并自动处理所有 API 差异。
| MongoDB 驱动版本 | 支持状态 | 测试状态 | 说明 |
|---|---|---|---|
| 4.x (4.17.2) | ✅ 完全支持 | ✅ 已测试 | 自动适配连接选项和返回值 |
| 5.x (5.9.2) | ✅ 完全支持 | ✅ 已测试 | 自动统一返回值格式 |
| 6.x (6.17.0) | ✅ 完全支持 | ✅ 已测试 | 推荐版本 ⭐⭐⭐⭐⭐ |
| 7.x+ | ⏸️ 待测试 | 未经测试,可能需要适配 |
package.json 中的声明:
{
"dependencies": {
"mongodb": "^6.17.0"
}
}说明:
^6.17.0表示兼容 6.17.0 到 <7.0.0 的所有版本- monSQLize 内部已处理 4.x/5.x/6.x 的差异
- 用户可以使用任意支持的版本,无需修改代码
这是最重要的差异,monSQLize 已完全自动处理。
Driver 4.x 返回格式:
const result = await collection.findOneAndUpdate(filter, update);
// result 格式:
{
value: { _id: ..., name: "Alice" }, // 文档
ok: 1, // 操作状态
lastErrorObject: { // 错误信息
n: 1,
updatedExisting: true
}
}Driver 5.x/6.x 返回格式(简化):
const result = await collection.findOneAndUpdate(filter, update);
// result 格式:
{
value: { _id: ..., name: "Alice" } // 只返回文档
}用户代码完全相同,无论使用哪个 Driver 版本:
// 使用 monSQLize,所有 Driver 版本返回格式统一
const user = await collection.findOneAndUpdate(
{ name: 'Alice' },
{ $set: { age: 31 } }
);
// ✅ 所有版本都返回统一格式:文档本身
console.log(user); // { _id: ..., name: "Alice", age: 31 }
// 不需要判断版本:
// ❌ 不需要: if (result.value) return result.value;
// ❌ 不需要: if (result.ok) return result;实现原理:
monSQLize 内部的 test/utils/version-adapter.js 自动检测 Driver 版本并统一返回值:
// monSQLize 内部自动处理
adaptFindOneAndUpdateResult(result) {
if (!result) return null;
// Driver 5.x/6.x: 直接返回 value
if (result.value !== undefined && !result.ok) {
return result.value;
}
// Driver 4.x: 提取 value
if (result.ok && result.value !== undefined) {
return result.value;
}
return result;
}适用的方法:
- ✅ findOneAndUpdate
- ✅ findOneAndReplace
- ✅ findOneAndDelete
console.log(result); // 输出: // { // value: { _id: ..., name: "Alice" }, // ok: 1, // lastErrorObject: { // updatedExisting: true, // n: 1 // } // }
**特点**:
- ✅ 默认返回完整元数据
- ✅ 包含 `value`(文档)、`ok`(状态)、`lastErrorObject`(详细信息)
- ✅ 可以直接判断操作是否成功
#### MongoDB 驱动 6.x
```javascript
// 默认行为(不带选项)
const result = await collection.findOneAndUpdate(filter, update);
console.log(result);
// 输出:
// { _id: ..., name: "Alice" } // 直接返回文档!
// 获取完整元数据(需要显式指定)
const result = await collection.findOneAndUpdate(filter, update, {
includeResultMetadata: true
});
console.log(result);
// 输出:
// {
// value: { _id: ..., name: "Alice" },
// ok: 1,
// lastErrorObject: {
// updatedExisting: true,
// n: 1
// }
// }
特点:
- ❌ 默认不返回元数据,直接返回文档
- ✅ 需要
includeResultMetadata: true才返回完整元数据 ⚠️ 破坏性变更:旧代码访问result.lastErrorObject会报错
| 方法 | 驱动 5.x | 驱动 6.x | 是否变化 |
|---|---|---|---|
| findOneAndUpdate | { value, ok, lastErrorObject } |
文档对象 | ✅ 已变化 |
| findOneAndReplace | { value, ok, lastErrorObject } |
文档对象 | ✅ 已变化 |
| findOneAndDelete | { value, ok, lastErrorObject } |
文档对象 | ✅ 已变化 |
| updateOne | { acknowledged, matchedCount, ... } |
相同 | ❌ 未变化 |
| updateMany | { acknowledged, matchedCount, ... } |
相同 | ❌ 未变化 |
| deleteOne | { acknowledged, deletedCount } |
相同 | ❌ 未变化 |
| deleteMany | { acknowledged, deletedCount } |
相同 | ❌ 未变化 |
| replaceOne | { acknowledged, matchedCount, ... } |
相同 |
注: replaceOne 的 modifiedCount 计算方式有微调,即使内容相同也可能返回 1。
monSQLize 使用适配层模式隔离驱动版本差异:
用户代码
↓
monSQLize 公共 API(保持不变)
↓
result-handler.js(适配层)← 处理驱动差异
↓
MongoDB 驱动(可能变化)
位置: lib/mongodb/writes/result-handler.js
职责:
- ✅ 统一处理
findOneAnd*的返回值 - ✅ 自动检测和适配驱动版本差异
- ✅ 提供一致的 API 行为
- ✅ 记录异常情况和版本警告
核心函数:
// 1. 处理返回值格式差异
handleFindOneAndResult(result, options, logger)
// 2. 安全判断文档是否被修改
wasDocumentModified(result)
// 3. 检测驱动版本
detectDriverVersion()
// 4. 输出版本警告
warnUnsupportedDriverVersion(logger)自动检测:
- 首次调用
findOneAnd*方法时自动检测驱动版本 - 检测逻辑:读取
require("mongodb").version或package.json
警告机制:
// 驱动版本 < 6.x
logger.warn("[result-handler] ⚠️ 检测到 MongoDB 驱动版本过旧", {
detectedVersion: 5,
supportedVersion: "6.x",
message: "monSQLize 专为 MongoDB 驱动 6.x 设计,旧版本可能存在兼容性问题",
recommendation: "建议升级到 MongoDB Node.js 驱动 ^6.0.0"
});
// 驱动版本 > 6.x
logger.warn("[result-handler] ⚠️ 检测到 MongoDB 驱动版本未经测试", {
detectedVersion: 7,
testedVersion: "6.x",
message: "monSQLize 已针对 MongoDB 驱动 6.x 测试,新版本可能存在未知问题",
recommendation: "如遇问题,请查看技术分析报告或回退到驱动 6.x"
});场景 1: result 为 null
// 驱动在某些边界情况可能返回 null
handleFindOneAndResult(null, {});
// 返回: null(用户视角正常)
// 日志输出
logger.debug("[result-handler] Result is null/undefined, returning empty result");场景 2: 缺少 lastErrorObject
// 驱动返回了非预期格式
const result = { _id: 1, name: "Alice" }; // 缺少 value 和 lastErrorObject
handleFindOneAndResult(result, {});
// 自动补充缺失字段
// 日志输出
logger.warn("[result-handler] ⚠️ Result missing lastErrorObject, possible driver version issue", {
hasValue: false,
resultKeys: ["_id", "name"],
driverVersion: 6,
recommendation: "这可能表明 MongoDB 驱动返回了非预期的格式,请检查驱动版本"
});当 MongoDB 发布新的主版本驱动时(如 7.x),请按以下步骤操作:
- 阅读 MongoDB 驱动的 CHANGELOG
- 重点关注
findOneAnd*方法的变更 - 查看是否有其他破坏性变更
官方资源:
# 1. 创建测试分支
git checkout -b test/mongodb-driver-upgrade
# 2. 升级驱动
npm install mongodb@^7.0.0
# 3. 运行完整测试套件
npm test
# 4. 检查测试结果
# - 关注 findOneAndUpdate 测试(22 个)
# - 关注 findOneAndDelete 测试(18 个)
# - 关注 findOneAndReplace 测试(20 个)
# - 关注 replaceOne 测试(24 个)# 运行测试并查看警告日志
npm test 2>&1 | grep "result-handler"
# 查找版本警告
npm test 2>&1 | grep "检测到 MongoDB 驱动版本"如果测试失败:
-
定位问题:
# 运行特定测试套件 npm test -- --grep "findOneAndUpdate"
-
分析错误:
- 是否是返回值格式变化?
- 是否是新增/删除的字段?
- 是否是行为逻辑变化?
-
修改适配层:
- 优先修改
result-handler.js - 保持公共 API 不变
- 添加新的驱动版本检测逻辑
- 优先修改
-
更新文档:
- 更新本文档的"支持的驱动版本"
- 更新 CHANGELOG.md
- 更新 API 文档中的兼容性说明
# 完整测试套件
npm test
# 覆盖率检查
npm run coverage
# 确保没有回归问题假设 MongoDB 驱动 7.x 再次改变了返回值格式:
场景: 驱动 7.x 返回 { document, metadata } 格式
// lib/mongodb/writes/result-handler.js
function handleFindOneAndResult(result, options = {}, logger = null) {
const driverVersion = detectDriverVersion();
// 驱动 7.x 的新格式
if (driverVersion >= 7) {
// 适配新格式
if (result && result.document !== undefined) {
// 转换为统一格式
result = {
value: result.document,
ok: 1,
lastErrorObject: result.metadata || { n: result.document ? 1 : 0 }
};
}
}
// 驱动 6.x 的处理逻辑(保持不变)
// ...existing code...
// 统一返回
if (options.includeResultMetadata) {
return result;
} else {
return result.value !== undefined ? result.value : null;
}
}关键点:
- ✅ 仅修改
result-handler.js - ✅ 公共 API 保持不变
- ✅ 用户代码无需修改
| 测试类型 | 测试用例数 | 说明 |
|---|---|---|
| findOneAndUpdate | 22 | 覆盖所有选项和边界情况 |
| findOneAndDelete | 18 | 覆盖排序、projection 等 |
| findOneAndReplace | 20 | 覆盖 upsert、缓存等 |
| replaceOne | 24 | 覆盖驱动行为变化 |
| 其他写操作 | 100+ | 确保无回归 |
必须测试的场景:
- ✅ 找到文档并修改
- ✅ 未找到文档(返回 null)
- ✅ upsert 插入新文档
- ✅ 返回更新前的文档(
returnDocument: "before") - ✅ 返回更新后的文档(
returnDocument: "after") - ✅ 包含完整元数据(
includeResultMetadata: true) - ✅ 缓存自动失效
- ✅ 并发安全性
# 运行所有测试
npm test
# 仅运行 findOneAnd* 测试
npm test -- --grep "findOneAnd"
# 测试覆盖率
npm run coverage
# 查看覆盖率报告
open coverage/index.html # macOS
start coverage/index.html # Windows如果未来需要添加类似的方法(如自定义的 findOneAndModify),请遵循以下模式:
// lib/mongodb/writes/custom-find-one-and-modify.js
const { handleFindOneAndResult, wasDocumentModified } = require("./result-handler");
async function customFindOneAndModify(filter, modification, options = {}) {
const { logger } = this.context;
try {
// 1. 强制获取完整元数据
const driverOptions = { ...options, includeResultMetadata: true };
// 2. 调用 MongoDB 驱动
const result = await nativeCollection.customMethod(filter, modification, driverOptions);
// 3. 判断是否需要失效缓存
const wasModified = wasDocumentModified(result);
if (cache && wasModified) {
// 缓存失效逻辑
}
// 4. 使用统一的返回值处理(传递 logger)
return handleFindOneAndResult(result, options, logger);
} catch (error) {
// 错误处理
}
}关键点:
- ✅ 使用
includeResultMetadata: true - ✅ 使用
wasDocumentModified()判断缓存失效 - ✅ 使用
handleFindOneAndResult()处理返回值 - ✅ 传递
logger参数用于诊断
-
技术分析报告:
analysis-reports/2025-11-17-mongodb-driver-6x-compatibility-FINAL.md- 详细的问题分析
- 修复方案对比
- 经验教训和最佳实践
-
API 文档:
docs/find-one-and-update.md- 包含兼容性说明docs/find-one-and-replace.md- 包含兼容性说明docs/find-one-and-delete.md- 包含兼容性说明
A: 理论上可以工作,但未经充分测试。建议升级到 6.x:
npm install mongodb@^6.17.0如果必须使用 5.x,请运行完整测试套件确认兼容性。
A: 检查 package-lock.json 或运行:
npm list mongodb或在代码中:
const mongodb = require("mongodb");
console.log("MongoDB Driver Version:", mongodb.version);A: 按照"未来驱动升级指南"操作:
- 查看失败的测试套件(特别是
findOneAnd*) - 分析错误日志
- 修改
result-handler.js适配新格式 - 保持公共 API 不变
如需帮助,请参考技术分析报告或提交 Issue。
A: 因为这些方法的返回值格式比较复杂(包含元数据),而其他方法(如 updateOne)的返回值格式简单且未变化。
A: 目前不计划支持多版本。原因:
- ✅ 增加维护成本
- ✅ 增加测试复杂度
- ✅ MongoDB 驱动遵循语义化版本,主版本间差异明确
推荐做法:随 MongoDB 驱动主版本升级而升级 monSQLize。
| 日期 | 版本 | 变更 |
|---|---|---|
| 2025-11-17 | 1.0 | 初始版本 - 添加驱动 6.x 兼容性说明 |
维护者: monSQLize 开发团队
联系方式: 通过 GitHub Issues 提问
最后审核: 2025-11-17