[{"data":1,"prerenderedAt":363},["ShallowReactive",2],{"content:\u002Fposts\u002F2025\u002Fnestjs-drizzle":3,"surround:\u002Fposts\u002F2025\u002Fnestjs-drizzle":352},{"id":4,"title":5,"body":6,"canonical":325,"categories":326,"date":328,"description":329,"draft":330,"extension":331,"image":332,"meta":333,"navigation":334,"path":335,"permalink":325,"readingTime":336,"recommend":325,"references":341,"seo":345,"sitemap":346,"stem":347,"tags":348,"type":325,"updated":350,"__hash__":351},"content\u002Fposts\u002F2025\u002Fnestjs-drizzle.md","在 Nestjs 中使用 Drizzle ORM",{"type":7,"value":8,"toc":292},"minimark",[9,13,24,28,39,48,56,62,73,79,85,91,95,103,109,115,121,124,128,135,141,145,153,169,173,179,185,192,196,203,207,214,217,221,231,234,237,246,250,257,261,268,275,279,285],[10,11,12],"h2",{"id":12},"依赖安装",[14,15,21],"pre",{"className":16,"code":18,"language":19,"meta":20},[17],"language-shell","pnpm add drizzle-orm pg dotenv\npnpm add -D drizzle-kit tsx @types\u002Fpg\n","shell","",[22,23,18],"code",{"__ignoreMap":20},[10,25,27],{"id":26},"准备-drizzlemodule","准备 DrizzleModule",[29,30,31],"p",{},[32,33,34,35,38],"strong",{},"这里我们都在 ",[22,36,37],{"code":37},"\u002Fsrc\u002Fdrizzle"," 目录中操作",[40,41,43,44,47],"h3",{"id":42},"创建-drizzleproviderts-文件","创建 ",[22,45,46],{"code":46},"drizzle.provider.ts"," 文件",[14,49,54],{"className":50,"code":52,"filename":46,"language":53,"meta":20},[51],"language-ts","import { Provider } from '@nestjs\u002Fcommon';\nimport { drizzle, NodePgDatabase } from 'drizzle-orm\u002Fnode-postgres';\nimport { Pool } from 'pg';\n\nimport { ConfigService } from '@\u002Fconfig\u002Fconfig.service';\n\nimport { Schema, schema } from '.\u002Fschema';\n\nexport const PG_CONNECTION = 'PG_CONNECTION';\n\nexport const DrizzleProvider: Provider = {\n    provide: PG_CONNECTION,\n    inject: [ConfigService],\n    useFactory(configService: ConfigService) {\n        const connectionString = configService.database.DATABASE_URL;\n        const pool = new Pool({ connectionString });\n        return drizzle(pool, { schema, logger: true }) as NodePgDatabase\u003CSchema>;\n    },\n};\n","ts",[22,55,52],{"__ignoreMap":20},[40,57,43,59,47],{"id":58},"创建-drizzleservicets-文件",[22,60,61],{"code":61},"drizzle.service.ts",[29,63,64,65,68,69,72],{},"有了这个以后，我们可以在后续的模块中直接注入该模块 ",[22,66,67],{"code":67},"constructor(private readonly drizzle: DrizzleService) {}","，而不是每次都要写 ",[22,70,71],{"code":71},"constructor(@Inject(PG_CONNECTION) readonly db: NodePgDatabase\u003CSchema>) {}"," 这么一长串内容",[14,74,77],{"className":75,"code":76,"filename":61,"language":53,"meta":20},[51],"import { Inject, Injectable } from '@nestjs\u002Fcommon';\nimport { NodePgDatabase } from 'drizzle-orm\u002Fnode-postgres';\n\nimport type { Schema } from '.\u002Fschema';\n\nimport { PG_CONNECTION } from '.\u002Fdrizzle.provider';\n\n@Injectable()\nexport class DrizzleService {\n    constructor(@Inject(PG_CONNECTION) readonly db: NodePgDatabase\u003CSchema>) {}\n}\n",[22,78,76],{"__ignoreMap":20},[40,80,43,82,47],{"id":81},"创建-drizzlemodulets-文件",[22,83,84],{"code":84},"drizzle.module.ts",[14,86,89],{"className":87,"code":88,"filename":84,"language":53,"meta":20},[51],"import { Global, Module } from '@nestjs\u002Fcommon';\n\nimport { DrizzleProvider } from '.\u002Fdrizzle.provider';\nimport { DrizzleService } from '.\u002Fdrizzle.service';\n\n@Global()\n@Module({\n    imports: [],\n    providers: [DrizzleService, DrizzleProvider],\n    exports: [DrizzleService],\n})\nexport class DrizzleModule {}\n",[22,90,88],{"__ignoreMap":20},[40,92,94],{"id":93},"创建数据库-schema","创建数据库 Schema",[96,97,99,100],"h4",{"id":98},"创建一个-userentityts","创建一个 ",[22,101,102],{"code":102},"user.entity.ts",[14,104,107],{"className":105,"code":106,"filename":102,"language":53,"meta":20},[51],"import { relations } from 'drizzle-orm';\nimport { pgTable, serial, timestamp, varchar } from 'drizzle-orm\u002Fpg-core';\nimport { createSelectSchema } from 'drizzle-zod';\nimport { z } from 'zod\u002Fv4';\n\nexport const timestamps = {\n    createdAt: timestamp('created_at').notNull().defaultNow(),\n    updatedAt: timestamp('updated_at').notNull().defaultNow(),\n};\n\nexport const user = pgTable('user', {\n    id: serial().primaryKey(),\n    username: varchar().notNull().unique(),\n    password: varchar().notNull(),\n    ...timestamps,\n});\n\nexport const selectUserSchema = createSelectSchema(user);\nexport type SelectUser = z.infer\u003Ctypeof selectUserSchema>;\n",[22,108,106],{"__ignoreMap":20},[96,110,43,112,47],{"id":111},"创建-schemats-文件",[22,113,114],{"code":114},"schema.ts",[14,116,119],{"className":117,"code":118,"filename":114,"language":53,"meta":20},[51],"import { user } from '.\u002Fuser.entity';\n\nexport type { SelectUser } from '.\u002Fuser.entity';\n\nexport const schema = {\n    user\n}\n\nexport type Schema = typeof schema;\nexport type SchemaName = keyof Schema;\n",[22,120,118],{"__ignoreMap":20},[29,122,123],{},"这样我们的 DrizzleModule 就准备好了",[10,125,127],{"id":126},"drizzle-相关的配置","drizzle 相关的配置",[29,129,130,131,134],{},"我们要在项目根目录下创建 ",[22,132,133],{"code":133},"drizzle.config.ts"," 文件，这个文件是 DrizzleOrm 的配置文件",[14,136,139],{"className":137,"code":138,"filename":133,"language":53,"meta":20},[51],"import 'dotenv\u002Fconfig';\nimport { defineConfig } from 'drizzle-kit';\n\nexport default defineConfig({\n    schema: '.\u002Fsrc\u002Fdrizzle\u002Fschema\u002F**.entity.ts', \u002F\u002F 这里是数据库 schema 文件的位置\n    out: '.\u002Fdrizzle\u002Fmigrations', \u002F\u002F 数据库迁移文件生成的地址\n    dialect: 'postgresql', \u002F\u002F 数据库驱动\n    dbCredentials: {\n        url: process.env.DATABASE_URL!,\n    },\n});\n",[22,140,138],{"__ignoreMap":20},[10,142,144],{"id":143},"packagejson-中的脚本","package.json 中的脚本",[14,146,151],{"className":147,"code":149,"language":150,"meta":20},[148],"language-json","{\n  \"scripts\": {\n    \"db:generate\": \"drizzle-kit generate\",\n    \"db:migrate\": \"drizzle-kit migrate\",\n    \"db:push\": \"drizzle-kit push\",\n    \"db:studio\": \"drizzle-kit studio\",\n  },\n}\n","json",[22,152,149],{"__ignoreMap":20},[154,155,156,160,163,166],"ul",{},[157,158,159],"li",{},"db:generate 声明时或后续 Schema 更改时基于 Drizzle Schema 生成 SQL 迁移",[157,161,162],{},"db:migrate 运行迁移后，Drizzle Kit 会将成功应用的迁移记录保存到数据库中。",[157,164,165],{},"db:push 允许您直接将您的架构和后续架构更改推送到数据库",[157,167,168],{},"db:studio 本地数据库可视化面板",[10,170,172],{"id":171},"生成-schema-并将改动同步到数据库","生成 schema 并将改动同步到数据库",[14,174,177],{"className":175,"code":176,"language":19,"meta":20},[17],"pnpm run db:generate\n",[22,178,176],{"__ignoreMap":20},[14,180,183],{"className":181,"code":182,"language":19,"meta":20},[17],"pnpm run db:migrate\n",[22,184,182],{"__ignoreMap":20},[29,186,187,188,191],{},"成功后我们可以使用 ",[22,189,190],{"code":190},"pnpm run db:studio"," 查看数据库中的内容。",[10,193,195],{"id":194},"在-appmodulets-中引入-drizzlemodule","在 app.module.ts 中引入 DrizzleModule",[14,197,201],{"className":198,"code":199,"filename":200,"language":53,"meta":20},[51],"@Module({\n    imports: [\n    \u002F\u002F ...\n        DrizzleModule,\n    ],\n})\nexport class AppModule {}\n","app.module.ts",[22,202,199],{"__ignoreMap":20},[10,204,206],{"id":205},"在模块中使用这里用-usermodule-作为例子","在模块中使用，这里用 UserModule 作为例子",[14,208,212],{"className":209,"code":210,"filename":211,"language":53,"meta":20},[51],"@Injectable()\nexport class UserService {\n    constructor(private readonly drizzle: DrizzleService) {}\n\n    async create(createUserDto: CreateUserDto) {\n        const result = await this.drizzle.db.insert(schema.user).values(createUserDto).returning();\n\n        return result;\n    }\n\n    async findOne(id: number) {\n        const [user] = await this.drizzle.db.select().from(schema.user).where(eq(schema.user.id, id));\n        return user;\n    }\n\n    async update(id: number, updateUserDto: UpdateUserDto) {\n        const user = this.drizzle.db\n            .update(schema.user)\n            .set(updateUserDto)\n            .where(eq(schema.user.id, id));\n        return user;\n    }\n\n    async remove(id: number) {\n        const [user] = await this.drizzle.db\n            .delete(schema.user)\n            .where(eq(schema.user.id, id))\n            .returning();\n        return user;\n    }\n}\n","user.service.ts",[22,213,210],{"__ignoreMap":20},[10,215,216],{"id":216},"附加内容",[40,218,220],{"id":219},"vscode-插件推荐","vscode 插件推荐",[222,223],"link-card",{"className":224,"description":227,"icon":228,"link":229,"title":230},[225,226],"gradient-card","active","这个插件可以让我们看到 drizzle 生成好的数据库模型图","https:\u002F\u002Form.drizzle.team\u002Ffavicon.ico","https:\u002F\u002Fopen-vsx.org\u002Fextension\u002Frphlmr\u002Fvscode-drizzle-orm","vscode-drizzle-orm",[40,232,233],{"id":233},"数据库填充",[29,235,236],{},"在开发中我们通常都要填充一些模拟数据用来测试，那么在 nestjs + drizzle 这个组合下我们如何操作呢?",[29,238,239],{},[32,240,241,242,245],{},"我们还是在 ",[22,243,244],{"code":244},"src\u002Fdrizzle"," 文件夹中操作",[96,247,249],{"id":248},"创建-dbts","创建 db.ts",[14,251,255],{"className":252,"code":253,"filename":254,"language":53,"meta":20},[51],"import 'dotenv\u002Fconfig';\nimport { drizzle, NodePgDatabase } from 'drizzle-orm\u002Fnode-postgres';\nimport { Pool } from 'pg';\n\nimport { Schema, schema } from '.\u002Fschema';\n\nconst connectionString = process.env.DATABASE_URL;\n\nif (!connectionString) {\n    throw new Error('DATABASE_URL is not defined');\n}\n\nconst pool = new Pool({ connectionString });\nexport const db: NodePgDatabase\u003CSchema> = drizzle(pool, { schema, logger: true });\n\nexport type db = NodePgDatabase\u003CSchema>;\n","db.ts",[22,256,253],{"__ignoreMap":20},[96,258,260],{"id":259},"创建-seed-相关文件","创建 seed 相关文件",[14,262,266],{"className":263,"code":264,"filename":265,"language":53,"meta":20},[51],"import 'dotenv\u002Fconfig';\nimport { Table } from 'drizzle-orm';\n\nimport { db } from '.\u002Fdb';\nimport { schema } from '.\u002Fschema';\nimport { seedUser } from '.\u002Fseeds\u002Fuser.seed';\n\n\u002F\u002F 清空数据库中的数据\nasync function clearTable() {\n    \u002F\u002F eslint-disable-next-line drizzle\u002Fenforce-delete-with-where\n    return await Promise.all(Object.values(schema).map((table: Table) => db.delete(table).execute()));\n}\n\nasync function seed() {\n    \u002F\u002F 每次填充前先将数据库中的数据清空\n    await clearTable();\n\n    \u002F\u002F 填充一些测试数据用来使用\n    await seedUser(db);\n}\n\nseed().catch((e) => {\n    console.error(e);\n    process.exit(0);\n});\n","seed.ts",[22,267,264],{"__ignoreMap":20},[14,269,273],{"className":270,"code":271,"filename":272,"language":53,"meta":20},[51],"import { hashSync } from 'bcrypt';\n\nimport { db } from '@\u002Fdrizzle\u002Fdb';\n\nimport { schema } from '..\u002Fschema';\n\nexport async function seedUser(db: db) {\n    await db.insert(schema.user).values([\n        { username: 'admin', password: hashSync('123456', 10) },\n        { username: 'user', password: hashSync('123456', 10) },\n    ]);\n}\n","seeds\u002Fuser.seed.ts",[22,274,271],{"__ignoreMap":20},[96,276,278],{"id":277},"在-packagejson-中添加命令","在 package.json 中添加命令",[14,280,283],{"className":281,"code":282,"language":150,"meta":20},[148],"{\n  \"db:seed\": \"ts-node .\u002Fsrc\u002Fdrizzle\u002Fseed.ts\",\n}\n",[22,284,282],{"__ignoreMap":20},[29,286,287,288,291],{},"我们就可以运行 ",[22,289,290],{"code":290},"pnpm run db:seed"," 来进行数据库填充了",{"title":20,"searchDepth":293,"depth":293,"links":294},4,[295,297,312,313,314,315,316,317],{"id":12,"depth":296,"text":12},2,{"id":26,"depth":296,"text":27,"children":298},[299,302,304,306],{"id":42,"depth":300,"text":301},3,"创建 drizzle.provider.ts 文件",{"id":58,"depth":300,"text":303},"创建 drizzle.service.ts 文件",{"id":81,"depth":300,"text":305},"创建 drizzle.module.ts 文件",{"id":93,"depth":300,"text":94,"children":307},[308,310],{"id":98,"depth":293,"text":309},"创建一个 user.entity.ts",{"id":111,"depth":293,"text":311},"创建 schema.ts 文件",{"id":126,"depth":296,"text":127},{"id":143,"depth":296,"text":144},{"id":171,"depth":296,"text":172},{"id":194,"depth":296,"text":195},{"id":205,"depth":296,"text":206},{"id":216,"depth":296,"text":216,"children":318},[319,320],{"id":219,"depth":300,"text":220},{"id":233,"depth":300,"text":233,"children":321},[322,323,324],{"id":248,"depth":293,"text":249},{"id":259,"depth":293,"text":260},{"id":277,"depth":293,"text":278},null,[327],"代码","2025-08-06 23:01:32","drizzle 是一个很好的 ORM 框架，但是它如何结合强大的 Nestjs 来使用呢？官方文档中并没有说明，我们这里做一点简单的“教程”，希望能对你有所帮助！",false,"md","https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002Fuse-drizzle-in-nestjs.jpg",{},true,"\u002Fposts\u002F2025\u002Fnestjs-drizzle",{"text":337,"minutes":338,"time":339,"words":340},"5 min read",4.795,287700,959,[342],{"title":343,"link":344},"drizzle","https:\u002F\u002Form.drizzle.team\u002F",{"title":5,"description":329},{"loc":335},"posts\u002F2025\u002Fnestjs-drizzle",[349,343],"nest","2025-08-10 23:40:32","Ai4JSSqRluZWwiHjKAKxjv_4W7Lv_nH4Wpk7OqUYdrc",[353,358],{"title":354,"path":355,"stem":356,"date":357,"type":325,"children":-1},"在 nestjs 中使用 scalar","\u002Fposts\u002F2025\u002Fnestjs-scalar","posts\u002F2025\u002Fnestjs-scalar","2025-08-02 11:44:47",{"title":359,"path":360,"stem":361,"date":362,"type":325,"children":-1},"在 Nestjs 中使用验证码","\u002Fposts\u002F2025\u002Fnest-captcha","posts\u002F2025\u002Fnest-captcha","2025-08-10 22:53:48",1789642588922]