You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB TypeScript模型:数据库snake_case与类camelCase映射方案问询

解决MongoDB Snake_Case与TypeScript CamelCase字段映射问题

针对你的需求——MongoDB字段用snake_case,TypeScript类用camelCase,同时保持两边命名规则不变,这里提供三种可行方案,从原生手动处理到成熟ODM工具都有覆盖:

方案一:基于标准MongoDB库手动实现字段转换

如果你不想引入额外依赖,可以自己编写字段转换函数,在读写数据库时做格式映射。

1. 定义TypeScript类(驼峰格式)

class User {
  constructor(
    public id?: string,
    public userName?: string,
    public emailAddress?: string,
    public createdAt?: Date
  ) {}
}

2. 实现驼峰/下划线转换函数(支持嵌套对象)

// 驼峰转下划线
function camelToSnake(obj: Record<string, any>): Record<string, any> {
  const result: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
      result[snakeKey] = typeof obj[key] === 'object' && obj[key] !== null
        ? camelToSnake(obj[key])
        : obj[key];
    }
  }
  return result;
}

// 下划线转驼峰
function snakeToCamel(obj: Record<string, any>): Record<string, any> {
  const result: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const camelKey = key.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
      result[camelKey] = typeof obj[key] === 'object' && obj[key] !== null
        ? snakeToCamel(obj[key])
        : obj[key];
    }
  }
  return result;
}

3. 读写数据库时应用转换

import { MongoClient, ObjectId } from 'mongodb';

// 插入数据:驼峰转下划线存入
async function createUser(user: User) {
  const client = await MongoClient.connect('mongodb://localhost:27017');
  const db = client.db('test');
  const snakeCaseData = camelToSnake(user);
  await db.collection('users').insertOne(snakeCaseData);
  await client.close();
}

// 查询数据:下划线转驼峰后实例化为类
async function getUserById(id: string): Promise<User | null> {
  const client = await MongoClient.connect('mongodb://localhost:27017');
  const db = client.db('test');
  const snakeCaseDoc = await db.collection('users').findOne({ _id: new ObjectId(id) });
  await client.close();
  
  if (!snakeCaseDoc) return null;
  const camelCaseData = snakeToCamel(snakeCaseDoc);
  return new User(
    camelCaseData.id,
    camelCaseData.userName,
    camelCaseData.emailAddress,
    camelCaseData.createdAt
  );
}

优缺点:完全可控,无额外依赖,但需要维护转换逻辑,适合小型项目或对依赖敏感的场景。

方案二:使用Mongoose ODM(推荐)

Mongoose作为MongoDB最常用的ODM,原生支持字段别名映射,能轻松实现驼峰与下划线的自动转换。

1. 安装依赖

npm install mongoose @types/mongoose

2. 定义Schema与实体类

可以通过插件批量添加驼峰别名,避免逐个字段配置:

import mongoose, { Schema } from 'mongoose';

// 定义TypeScript类
class UserClass extends mongoose.Document {
  userName!: string;
  emailAddress!: string;
  createdAt!: Date;
}

// 定义Schema,数据库字段用下划线
const userSchema = new Schema({
  user_name: { type: String, required: true },
  email_address: { type: String, required: true },
  created_at: { type: Date, default: Date.now }
});

// 批量添加驼峰别名的插件
function camelCaseAliasPlugin(schema: Schema) {
  schema.eachPath(path => {
    if (path.includes('_')) {
      const camelCasePath = path.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
      schema.path(path).alias(camelCasePath);
    }
  });
}

// 应用插件并关联类
userSchema.plugin(camelCaseAliasPlugin);
userSchema.loadClass(UserClass);

// 创建Model
const UserModel = mongoose.model<UserClass>('User', userSchema);

3. 操作数据库

直接用驼峰字段读写,Mongoose会自动转换为下划线存入数据库:

// 初始化连接
async function connectDB() {
  await mongoose.connect('mongodb://localhost:27017/test');
}

// 创建用户
async function createUser(user: Partial<UserClass>) {
  await connectDB();
  const newUser = new UserModel(user);
  await newUser.save();
}

// 查询用户
async function getUserById(id: string): Promise<UserClass | null> {
  await connectDB();
  return UserModel.findById(id);
}

优缺点:成熟稳定,自带验证、中间件等功能,TypeScript支持完善,适合中大型项目;唯一不足是引入了额外依赖,但学习成本低,生态完善。

方案三:使用TypeORM(跨数据库ORM)

如果你熟悉TypeORM或需要跨数据库支持,它也能通过装饰器指定MongoDB的字段名。

1. 安装依赖

npm install typeorm mongodb @types/mongodb

2. 定义实体类

通过@Column装饰器的name属性指定数据库的下划线字段:

import { Entity, Column, ObjectIdColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class User {
  @ObjectIdColumn()
  id?: string;

  @Column({ name: 'user_name', nullable: false })
  userName: string;

  @Column({ name: 'email_address', nullable: false })
  emailAddress: string;

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;
}

3. 配置连接与操作

import { createConnection, getRepository } from 'typeorm';

// 初始化连接
async function initDB() {
  await createConnection({
    type: 'mongodb',
    url: 'mongodb://localhost:27017/test',
    entities: [User],
    synchronize: true // 开发环境自动同步结构,生产环境建议关闭
  });
}

// 创建用户
async function createUser(user: User) {
  await initDB();
  const userRepo = getRepository(User);
  await userRepo.save(user);
}

// 查询用户
async function getUserById(id: string) {
  await initDB();
  const userRepo = getRepository(User);
  return userRepo.findOne(id);
}

优缺点:跨数据库支持强,TypeScript集成度高,装饰器写法优雅;但MongoDB的高级功能支持不如Mongoose,适合需要同时操作多种数据库的场景。

内容的提问来源于stack exchange,提问作者Sebastijan Kelneric

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:01:13