这篇文章主要盘点 Node.js 生态的 ORM 或者数据操作工具库,这些 ORM 或者工具库能够帮助我们快捷的操作数据库。

一、直接操作 SQL

如果你熟练使用 sql 语句,其实也不需要 ORM, ORM 就是图方便。下面我们就是开始了解 Node.js 社区的各种 ORM或者 ODM。

二、Prisma ORM

Prisma 是最为流行的 ORM, 目前 Prisma 的模型已经开始支持多文件,这解决一个文件中写所有的问题。

2.1)资源

2.2)Prisma 特性

  • 🌴基于 TypeScript 类型安全,自动生成操作数据 API
  • 🌴自创了 Prisma.schema PSL 文件,简洁明了(目前已经支持多文件)
  • 🌴多数据库抽象支持,无需关注底层
  • 🌴良好的 CLI 命令支持,自动化迁移(不是数据库之间)
  • 🌴良好的文档和社区支持

2.3)Primsa 使用示例

使用 Prisma 你需要熟悉 Primsa 使用流程:

prisma -> init -> schema -> migrate -> 使用 primsa 客户客户端操作数据库。


sh

复制代码

cd your_dir pnpm init pnpm add prisma ts-node -D pnpm npx prisma init # 默认是 pg

写一个 User 模型


ts

复制代码

model User { id Int @id @default(autoincrement()) email String @unique name String? password String }

🉑现在 Prisma 已经支持多个 schema 写模型,并且 vscode 插件也得到了很好的跳转支持。所以 Prisma 是值得学习和使用的。

  • 🍎使用迁移生成客户端

sh

复制代码

npx prisma migrate dev --name init

  • 使用客户端操作 api

ts

复制代码

import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() async function user() { const user = await primsa.user.create({ email: 'your_email', name: 'your_name', password: 'your_password' }) return user } user().then((user) => { /* handler*/}).catch(() => /* catch error*/)

  • 🍎prisma studio

sh

复制代码

npx prisma studio # 默认端口 5555

提供一个浏览器版本的数据库操作软件,可以很直观的观察和处理数据。

如果下载有问题,设置环境变量 PRISMA_ENGINES_MIRROR=https://registry.npmmirror.com/-/binary/prisma

三、TypeORM

3.1)资源

  • 🌹typeorm typeorm 官方网站和文档库
  • 🌹typeorm 代码托管地址
  • 🌹typeorm npm 包管理

3.2)TypeORM 特性

  • 🌴基于 TypeScript 类型安全,支持 JavaScript/ESM, Class 实体、语法灵活
  • 🌴支持 DataMapper 和 ActiveRecord 两种模式
  • 🌴直接关系模型(关联,单项、双向、自引用、连接)
  • 🌴连接池、支持过数据库实例
  • 🌴多数据库支持
  • 🌴自动迁移和生成迁移文件
  • ...

3.3)TypeORM 使用示例

使用 TypeORM 你需要熟悉 TypeORM 使用流程:


sh

复制代码

pnpm install typeorm reflect-metadata pnpm install @types/node -D # 安装驱动器,驱动器其实就是之前提到直接操作 sql 的库。

配置 typescript 的配置文件


json

复制代码

"emitDecoratorMetadata": true, "experimentalDecorators": true,

  • 🍎使用 cli 快速开始

sh

复制代码

npx typeorm init --name MyProject --database postgres

typeorm -> Entity -> Repository -> save/find/findOneBy/remove

  • 定义实体类(并配置列属性)

ts

复制代码

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm" @Entity() export class User { @PrimaryGeneratedColumn() // 自增长列 id: number @Column() firstName: string @Column() lastName: string @Column() age: number }

  • 🍎初始化 DataSource

ts

复制代码

import "reflect-metadata" import { DataSource } from "typeorm" import { User } from "./entity/User" export const AppDataSource = new DataSource({ // other... entities: [User], })

  • 🍎操作实体类型

ts

复制代码

import { AppDataSource } from "./data-source" import { User } from "./entity/User" AppDataSource.initialize().then(async () => { const user = new User(); // 实例化实体,然后修改实体属性 user.firstName = "Timber" user.lastName = "Saw" user.age = 25 await AppDataSource.manager.save(user) // 保存实体 const users = await AppDataSource.manager.find(User) // 查找实体 }).catch(error => console.log(error))

通过以上操作可以看出 typeorm 亲近 TypeScript 的 class, 在 class 基础上操作数据库。

四、Sequelize

4.1)资源

4.2)Sequelize 特性

  • 🍎TypeScript 和 Node.js ORM 数据库支持
  • 🍎多种数据库支持,支持事务

4.3)Sequelize 使用示例


sh

复制代码

pnpm add express sequelize sqlite3 npx sequelize-cli init

sqlite3 可能会安装的慢一点,可能是 node-pre-gyp 造成的。可能需要切换源。

cli 会自动创建:

  • 🌴config/config.json 配置文件
  • 🌴migrations 迁移文件夹
  • 🌴models 模型文件夹
  • 🌴seeders 种子文件夹
  • 执行迁移命令 npx sequelize-cli db:migrate, 会自动生成 SquelizeMeta 表只有一个字段 name

添加模型文件并执行迁移:


js

复制代码

'use strict'; const { Model, DataTypes } = require('sequelize'); module.exports = (sequelize) => { class User extends Model { static associate(models) { // Define associations here } } User.init( { firstName: DataTypes.STRING, lastName: DataTypes.STRING, email: { type: DataTypes.STRING, unique: true, }, age: DataTypes.INTEGER, }, { sequelize, modelName: 'User', } ); return User; };


sh

复制代码

npx sequelize-cli db:migrate

迁移之后数据中就会添加 User 表。基于 rexpress 写一个接口操作数据


ts

复制代码

const express = require('express'); const router = express.Router(); const db = require('../models'); router.post('/', async (req, res) => { try { const { firstName, lastName, email, age } = req.body; const newUser = await db.User.create({ firstName, lastName, email, age }); res.json(newUser); } catch (error) { res.status(500).json({ error: 'An error occurred while creating the user' }); } }); module.exports = router;

五、Mongoose (ODM)

5.1)资源

5.2)Mongoose 特性

  • 🍎Mongoose 专门为 mongodb 的 ODM 对象文档模型
  • 🍎箱即用的内置类型转换、验证、查询构建、业务逻辑挂钩等

sh

复制代码

pnpm add express mongoose

5.3)Mongoose 使用示例

从 schema 到 model 模型,再到操作模型


ts

复制代码

const mongoose = require('mongoose'); mongoose.connect('mongodb://127.0.0.1:27017/test'); const animalSchema = new Schema({ name: String, password: string }); const AnimalModel = mongoose.model('Animal', animalSchema); const animals = await Animal.find(); const animal = await Animal.findById(id); const updatedAnimal = await Animal.findByIdAndUpdate(id, { name, password }, { new: true }); const deletedAnimal = await Animal.findByIdAndDelete(id);

六、drizzle

6.1)drizzle 资源

6.2)drizzle 特性

  • 🍎Drizzle ORM 是一个有头的无头 TypeScript ORM 🐲
  • 🍎如果您了解 SQL,那么您就了解 Drizzle。
  • 🍎支持主流的数据库和 serverless

6.3)drizzle 使用示例


sh

复制代码

pnpm add drizzle-orm dotenv better-sqlite3 drizzle-kit pnpm add -D esno

drizzle-orm 有众多的 数据库 相关的库的支持。

有一个公式:drizzle + client/connection/... -> migrate -> db, 主要是操作这个 db。

  • 🍎创建 schema.ts 文件

ts

复制代码

import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; import { sql } from "drizzle-orm"; export const users = sqliteTable('users', { id: text('id'), textModifiers: text('text_modifiers').notNull().default(sql`CURRENT_TIMESTAMP`), intModifiers: integer('int_modifiers', { mode: 'boolean' }).notNull().default(false), }); export type User = typeof users.$inferSelect export type InsertUser = typeof users.$inferInsert

  • 🍎配置文件

ts

复制代码

import { defineConfig } from 'drizzle-kit'; export default defineConfig({ schema: './schema.ts', out: './drizzle', dialect: 'sqlite', // 'postgresql' | 'mysql' | 'sqlite' });

迁移一次:


sh

复制代码

pnpm drizzle-kit generate

  • 🍎创建 db.ts

ts

复制代码

// src/db.ts import * as schema from "../schema"; import Database from "better-sqlite3"; import { drizzle } from "drizzle-orm/better-sqlite3"; const sqlite = new Database("sqlite.db"); export const db = drizzle(sqlite, { schema });

  • 创建迁移文件

ts

复制代码

// src/migrate.ts import "dotenv/config"; import { db } from "./db"; import { migrate } from "drizzle-orm/better-sqlite3/migrator"; // This will run migrations on the database, skipping the ones already applied async function migrate_run() { return await migrate(db, { migrationsFolder: "./drizzle" }); } migrate_run() .then((res) => console.log(res)) .catch((error) => console.log(error));

执行迁移:


sh

复制代码

pnpm tsx src/migrate.ts

sqlite 数据库包含两条个表:

  • __dirzzle_migrations
  • users

后面就可以愉快的加入到框架中了,总体而言drizzle 有 ORM 模型,会生成 sql 语句,需要迁移,灵活性较强。

七、mikro-orm

7.1)mikro-orm 资源

  • 🌹mikro mikro 官方网站
  • 🌹mikro docs 文档库
  • 🌹mikro blog 博客(会发一些新的消息和新的功能)
  • 🌹mikro 代码托管地址
  • 🌹mikro npm 包管理

7.2)mikro-orm 特性

  • Node.js 的 TypeScript ORM 基于数据映射器、工作单元和身份映射模式。
  • 支持主流的数据库

7.3)示例

本示例基于 sqlite,主要分为以下几个步骤:

  • 🍎安装依赖

sh

复制代码

pnpm add express @mikro-orm/core @mikro-orm/better-sqlite @mikro-orm/sql-highlighter

  • 🍎定义配置文件

ts

复制代码

import { defineConfig } from '@mikro-orm/better-sqlite'; import { SqlHighlighter } from '@mikro-orm/sql-highlighter'; export default defineConfig({ dbName: 'your_db', highlighter: new SqlHighlighter(), });

在 package.json 中指定配置文件位置:


json

复制代码

"mikro-orm": { "configPaths": [ "./app/mikro-orm.config.js" ] }

  • 🍎定义一个实体

ts

复制代码

'use strict'; import { Collection, EntitySchema } from '@mikro-orm/core'; import { Book } from './Book.js'; import { BaseEntity } from './BaseEntity.js'; export class Author extends BaseEntity { constructor(name, email) { super(); this.name = name; this.email = email; this.termsAccepted = false; } } Author.beforeDestroyCalled = 0; Author.afterDestroyCalled = 0; export const schema = new EntitySchema({ class: Author, extends: 'BaseEntity', properties: { name: { type: 'string' }, email: { type: 'string' }, age: { type: 'number', nullable: true }, termsAccepted: { type: 'boolean' }, identities: { type: 'string[]', nullable: true }, born: { type: 'Date', nullable: true }, books: { kind: '1:m', mappedBy: 'author', type: 'Book', }, favouriteBook: { kind: 'm:1', type: 'Book', nullable: true, }, }, });

  • 🍎在 express 中间件中全局注册

ts

复制代码

import { EntityManager, EntityRepository, MikroORM, RequestContext } from '@mikro-orm/better-sqlite'; import config from './mikro-orm.config.js'; import { Author } from './entities/index.js'; export const DI = {}; DI.orm = await MikroORM.init(config); DI.em = DI.orm.em; DI.authors = DI.orm.em.getRepository(Author); // 指定 DI Author 方便操作 app.use((req, res, next) => { RequestContext.create(DI.orm.em, next); req.di = DI; });

  • 🍎获取和修改

ts

复制代码

import { DI } from '../server.js'; router.get('/', async (req, res) => { const authors = await DI.authors.findAll({ populate: ['books'], orderBy: { name: QueryOrder.DESC }, limit: 20, }); res.json(authors); }); router.post('/', async (req, res) => { if (!req.body.name || !req.body.email) { res.status(400); return res.json({ message: 'One of `name, email` is missing' }); } try { const author = DI.em.create(Author, req.body); await DI.em.flush(); res.json(author); } catch (e) { return res.status(400).json({ message: e.message, stack: e.stack }); } });

在开始运行之前还有一个重要的步骤就是: npx mikro-orm schema:create -r 生成 schema。然后就可以自由的操作数据了,添加功能。当然 cli 在后续也十分重要,根据自己的情况学习和补充。

八、Knex.js

8.1)资源

  • 🌹knexjs knexjs 官方网站和文档
  • 🌹knexjs 代码托管地址
  • 🌹knexjs npm 包管理

8.2)Knex.js 特性

  • 🌳定位是 基于 JavaScript 的 SQL 查询生成器。
  • 🌳主流的数据库均支持、支持 TypeScript。

Knex.js 干了一件非常核心的事情,就是将原来的 SQL 语句抽象为 JavaScript 函数。我们来看看对比:


ts

复制代码

// 初始化 Knex const knex = require('knex')({ client: 'mysql', // 或者 'pg', 'sqlite3', 'oracle' 等 connection: { host: '127.0.0.1', user: 'your_database_user', password: 'your_database_password', database: 'myapp_test' } }); // 构建一个 SELECT 查询: SELECT * FROM users WHERE id = 1; knex.select('*').from('users').where('id', 1) .then(rows => { console.log(rows); }) .catch(err => { console.error(err); }); // 插入数据: INSERT INTO users (name, age) VALUES ('John Doe', 28); knex('users').insert({name: 'John Doe', age: 28}) .then(() => { console.log('Data inserted'); }) .catch(err => { console.error(err); }); // 更新数据: UPDATE users SET name = 'Jane Doe' WHERE id = 1; knex('users').where('id', 1).update({name: 'Jane Doe'}) .then(() => { console.log('Data updated'); }) .catch(err => { console.error(err); }); // 删除数据: DELETE FROM users WHERE id = 1; knex('users').where('id', 1).del() .then(() => { console.log('Data deleted'); }) .catch(err => { console.error(err); });

8.3)构建在 Knex.js 之上

九、小结

这些 ORM 或者库,使用起来都差不多,功能也差不多,多数据库支持,有的基于使用模型,有的有基于实体类,然后在其基础上操作数据库。像 prisma 和 drizze 还提供了 studio 这种可是工具。有的提供了数据库的迁移工具,体验更加完整,整体你需要熟悉模型、需要熟悉实体、需要 sql 和 ORM 的映射,还需要 cli 工具,这一整套内容。最后希望能够帮助到大家。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐