Skip to content

MongoDB/MariaDB ID 兼容与归一化实战

适用场景:在 MongoDB/MariaDB 间切换或双活开发时,避免因主键类型差异导致的查询/比较错误。底层依据:app/repository/base/BaseStandardRepository.jsnormalizeIdcompareIdnormalizeQueryParams

TL;DR

  • Repository 构造函数会根据 config.repository.databaseType(默认 mongodb)决定 ID 处理方式
  • normalizeId 会把 MariaDB 模式下的纯数字字符串转 number,MongoDB 模式保持 string
  • normalizeQueryParams 统一处理 id/userId/typeId 等常见字段,减少 $in/$eq 失效
  • compareId 在业务逻辑中替代直接 ===,避免字符串与数字比较错误

实操要点

  1. 注册模型映射:子类调用 registerModel(含 relations)后,转换器会记录字段映射,transformIdFields 可在入库/出库时统一 ID 形态。
  2. 预处理查询:查询入口先调用 normalizeQueryParams(payload.query),或在自定义方法中对关键 ID 字段执行 normalizeId
  3. 写操作前转换:创建/更新时可通过 _mapIdToDatabase 将业务层 _id/id 映射为数据库格式,返回时用 _mapIdFromDatabase
  4. 比较与过滤:需要判断用户/作者等是否匹配时调用 compareId(a, b),减少数据库切换后的逻辑分支。
  5. 调试与日志:开启 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 中统一处理),确保数组内类型与数据库一致。

最后更新于: