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
相关产品推荐
相关产品推荐

