MongoDB/MariaDB ID 兼容与归一化实战
适用场景:在 MongoDB/MariaDB 间切换或双活开发时,避免因主键类型差异导致的查询/比较错误。底层依据:app/repository/base/BaseStandardRepository.js 的 normalizeId、compareId、normalizeQueryParams。
TL;DR
- Repository 构造函数会根据
config.repository.databaseType(默认 mongodb)决定 ID 处理方式 normalizeId会把 MariaDB 模式下的纯数字字符串转 number,MongoDB 模式保持 stringnormalizeQueryParams统一处理 id/userId/typeId 等常见字段,减少$in/$eq失效compareId在业务逻辑中替代直接===,避免字符串与数字比较错误
实操要点
- 注册模型映射:子类调用
registerModel(含 relations)后,转换器会记录字段映射,transformIdFields可在入库/出库时统一 ID 形态。 - 预处理查询:查询入口先调用
normalizeQueryParams(payload.query),或在自定义方法中对关键 ID 字段执行normalizeId。 - 写操作前转换:创建/更新时可通过
_mapIdToDatabase将业务层_id/id映射为数据库格式,返回时用_mapIdFromDatabase。 - 比较与过滤:需要判断用户/作者等是否匹配时调用
compareId(a, b),减少数据库切换后的逻辑分支。 - 调试与日志:开启
config.repository.logging = true可在仓储内记录操作日志,辅助排查类型不一致问题。
样例代码片段
js
// 自定义仓储示例
class ContentRepository extends BaseStandardRepository {
constructor(ctx) {
super(ctx, 'Content');
this.registerModel({ relations: { author: { path: 'author', select: ['userName'] } } });
}
async findByAuthor(authorId, payload = {}) {
const normalized = this.normalizeId(authorId);
const query = this.normalizeQueryParams({ author: normalized });
const params = this._standardizeParams(payload, { filters: query });
const result = await this.adapter.find(params);
return this._processResult(result, payload);
}
}常见问题 FAQ
- 切换 MariaDB 后
_id查询失效?
先确认DATABASE_TYPE=mariadb,再在仓储层用normalizeId/normalizeQueryParams处理查询条件,避免字符串 ID 直接用于数字主键。 - 不同服务返回的 ID 形态不一致?
在返回前调用_mapIdFromDatabase或在_customProcessDataItem中统一格式,前端就能拿到一致的字符串 ID。 - $in 查询混合类型导致空结果?
对$in数组先调用normalizeId(可在normalizeQueryParams中统一处理),确保数组内类型与数据库一致。