如何从 Mongoose 迁移到 Prisma ORM
介绍
¥Introduction
本指南将向你展示如何将应用从 Mongoose 迁移到 Prisma ORM。我们将使用 Mongoose Express 示例 的扩展版本作为 示例项目 来演示迁移步骤。
¥This guide shows you how to migrate your application from Mongoose to Prisma ORM. We'll use an extended version of the Mongoose Express example as a sample project to demonstrate the migration steps.
你可以在 Prisma ORM 与 Mongoose 页面上了解 Prisma ORM 与 Mongoose 的比较。
¥You can learn how Prisma ORM compares to Mongoose on the Prisma ORM vs Mongoose page.
先决条件
¥Prerequisites
在开始本指南之前,请确保你已准备好:
¥Before starting this guide, make sure you have:
-
你想要迁移的 Mongoose 项目
¥A Mongoose project you want to migrate
-
已安装 Node.js(版本 18 或更高版本)
¥Node.js installed (version 18 or higher)
-
MongoDB 数据库
¥MongoDB database
-
基本了解 Mongoose 和 Express.js
¥Basic familiarity with Mongoose and Express.js
1. 准备迁移
¥ Prepare for migration
1.1.了解迁移过程
¥1.1. Understand the migration process
无论你构建的是哪种应用或 API 层,从 Mongoose 迁移到 Prisma ORM 的步骤始终相同:
¥The steps for migrating from Mongoose to Prisma ORM are always the same, no matter what kind of application or API layer you're building:
-
安装 Prisma CLI
¥Install the Prisma CLI
-
检查你的数据库
¥Introspect your database
-
安装并生成 Prisma 客户端
¥Install and generate Prisma Client
-
逐步用 Prisma 客户端替换 Mongoose 查询
¥Gradually replace your Mongoose queries with Prisma Client
无论你是在构建 REST API(例如,使用 Express、Koa 或 NestJS)、GraphQL API(例如,使用 Apollo Server、TypeGraphQL 或 Nexus),还是任何其他使用 Mongoose 进行数据库访问的应用,这些步骤都适用。
¥These steps apply whether you're building a REST API (e.g., with Express, Koa, or NestJS), a GraphQL API (e.g., with Apollo Server, TypeGraphQL, or Nexus), or any other kind of application that uses Mongoose for database access.
1.2.设置 Prisma 配置
¥1.2. Set up Prisma configuration
创建一个新的 Prisma 模式文件:
¥Create a new Prisma schema file:
npx prisma init --datasource-provider mongodb --output ../generated/prisma
此命令将创建:
¥This command creates:
-
一个名为
prisma的新目录,其中包含一个schema.prisma文件;你的 Prisma 模式指定了你的数据库连接和模型¥A new directory called
prismathat contains aschema.prismafile; your Prisma schema specifies your database connection and models -
.env:一个位于项目根目录的dotenv文件(如果该文件尚不存在),用于将数据库连接 URL 配置为环境变量¥
.env: Adotenvfile at the root of your project (if it doesn't already exist), used to configure your database connection URL as an environment variable
Prisma 模式目前如下所示:
¥The Prisma schema currently looks as follows:
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
为了在使用 Prisma ORM 时获得最佳开发体验,请参阅 编辑器设置 了解语法高亮、格式化、自动补齐以及更多精彩功能。
¥For an optimal development experience when working with Prisma ORM, refer to editor setup to learn about syntax highlighting, formatting, auto-completion, and many more cool features.
使用 MongoDB 连接字符串更新 .env 文件中的 DATABASE_URL:
¥Update the DATABASE_URL in the .env file with your MongoDB connection string:
DATABASE_URL="mongodb://USER:PASSWORD@HOST:PORT/DATABASE"
2. 迁移数据库模式
¥ Migrate the database schema
2.1.检查你的数据库
¥2.1. Introspect your database
MongoDB 是一个无模式数据库。要在你的项目中逐步采用 Prisma ORM,请确保你的数据库中已填充示例数据。Prisma ORM 通过对存储的数据进行采样并从数据库中的数据推断出模式来自检 MongoDB 模式。
¥MongoDB is a schemaless database. To incrementally adopt Prisma ORM in your project, ensure your database is populated with sample data. Prisma ORM introspects a MongoDB schema by sampling data stored and inferring the schema from the data in the database.
运行 Prisma 的自省功能,从现有数据库创建 Prisma 模式:
¥Run Prisma's introspection to create the Prisma schema from your existing database:
npx prisma db pull
这将创建一个包含数据库架构的 schema.prisma 文件。
¥This will create a schema.prisma file with your database schema.
type UsersProfile {
bio String
}
model categories {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
name String
}
model posts {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
author String @db.ObjectId
categories String[] @db.ObjectId
content String
published Boolean
title String
}
model users {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
email String @unique(map: "email_1")
name String
profile UsersProfile?
}
2.2.更新关系
¥2.2. Update relations
MongoDB 不支持不同集合之间的关系。但是,你可以使用 ObjectId 字段类型在文档之间创建引用,或者使用集合中的 ObjectIds 数组在文档之间创建引用。该引用将存储相关文档的 ID。你可以使用 Mongoose 提供的 populate() 方法,将相关文档的数据填充到引用中。
¥MongoDB doesn't support relations between different collections. However, you can create references between documents using the ObjectId field type or from one document to many using an array of ObjectIds in the collection. The reference will store id(s) of the related document(s). You can use the populate() method that Mongoose provides to populate the reference with the data of the related document.
更新 posts <-> users 之间的 1-n 关系,如下所示:
¥Update the 1-n relationship between posts <-> users as follows:
-
将
posts模型中现有的author引用重命名为authorId,并添加@map("author")属性¥Rename the existing
authorreference in thepostsmodel toauthorIdand add the@map("author")attribute -
在
posts模型中添加author关系字段,并在其@relation属性中指定fields和references¥Add the
authorrelation field in thepostsmodel and it's@relationattribute specifying thefieldsandreferences -
在
users模型中添加posts关系¥Add the
postsrelation in theusersmodel
你的模式现在应该如下所示:
¥Your schema should now look like this:
type UsersProfile {
bio String
}
model categories {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
name String
}
model posts {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
published Boolean
v Int @map("__v")
author String @db.ObjectId
author users @relation(fields: [authorId], references: [id])
authorId String @map("author") @db.ObjectId
categories String[] @db.ObjectId
}
model users {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
email String @unique(map: "email_1")
name String
profile UsersProfile?
posts posts[]
}
然后,更新 posts <-> categories 引用之间的 m-n,如下所示:
¥Then, update the m-n between posts <-> categories references as follows:
-
将
categories字段重命名为categoryIds,并在posts模型中使用@map("categories")进行映射¥Rename the
categoriesfield tocategoryIdsand map it using@map("categories")in thepostsmodel -
在
posts模型中添加新的categories关系字段¥Add a new
categoriesrelation field in thepostsmodel -
在
categories模型中添加postIds标量列表字段¥Add the
postIdsscalar list field in thecategoriesmodel -
在
categories模型中添加posts关系¥Add the
postsrelation in thecategoriesmodel -
在两个模型上都添加 关系标量
¥Add a relation scalar on both models
-
添加
@relation属性,并在两端指定fields和references参数。¥Add the
@relationattribute specifying thefieldsandreferencesarguments on both sides
你的模式现在应该如下所示:
¥Your schema should now look like this:
type UsersProfile {
bio String
}
model categories {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
name String
posts posts[] @relation(fields: [postIds], references: [id])
postIds String[] @db.ObjectId
}
model posts {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
published Boolean
v Int @map("__v")
author users @relation(fields: [authorId], references: [id])
authorId String @map("author") @db.ObjectId
categories String[] @db.ObjectId
categories categories[] @relation(fields: [categoryIds], references: [id])
categoryIds String[] @map("categories") @db.ObjectId
}
model users {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
email String @unique(map: "email_1")
name String
profile UsersProfile?
posts posts[]
}
3. 更新你的应用代码
¥ Update your application code
3.1.安装 Prisma 客户端
¥3.1. Install Prisma Client
安装 Prisma 客户端包:
¥Install the Prisma Client package:
npm install @prisma/client
安装 Prisma 客户端软件包后,生成 Prisma 客户端:
¥After installing the Prisma Client package, generate Prisma Client:
npx prisma generate
3.2.替换 Mongoose 查询
¥3.2. Replace Mongoose queries
开始使用 Prisma 客户端替换你的 Mongoose 查询。以下是如何转换一些常见查询的示例:
¥Start replacing your Mongoose queries with Prisma Client. Here's an example of how to convert some common queries:
- Mongoose
- Prisma Client
// Find one
const user = await User.findById(id);
// Create
const user = await User.create({
email: 'alice@prisma.io',
name: 'Alice'
});
// Update
await User.findByIdAndUpdate(id, {
name: 'New name'
});
// Delete
await User.findByIdAndDelete(id);
// Find one
const user = await prisma.user.findUnique({
where: { id }
});
// Create
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
name: 'Alice'
}
});
// Update
await prisma.user.update({
where: { id },
data: { name: 'New name' }
});
// Delete
await prisma.user.delete({
where: { id }
});
3.3.更新你的控制器
¥3.3. Update your controllers
更新 Express 控制器以使用 Prisma 客户端。例如,以下是如何更新用户控制器:
¥Update your Express controllers to use Prisma Client. For example, here's how to update a user controller:
import { prisma } from '../client'
export class UserController {
async create(req: Request, res: Response) {
const { email, name } = req.body
const result = await prisma.user.create({
data: {
email,
name,
},
})
return res.json(result)
}
}
下一步
¥Next steps
现在你已经迁移到 Prisma ORM,你可以:
¥Now that you've migrated to Prisma ORM, you can:
-
使用 Prisma 强大的查询 API 添加更复杂的查询
¥Add more complex queries using Prisma's powerful query API
-
设置 Prisma Studio 进行数据库管理
¥Set up Prisma Studio for database management
-
实现数据库监控
¥Implement database monitoring
-
使用 Prisma 的测试实用程序
¥Add automated tests using Prisma's testing utilities
更多信息:
¥For more information:
Stay connected with Prisma
Continue your Prisma journey by connecting with our active community. Stay informed, get involved, and collaborate with other developers:
- Follow us on X for announcements, live events and useful tips.
- Join our Discord to ask questions, talk to the community, and get active support through conversations.
- Subscribe on YouTube for tutorials, demos, and streams.
- Engage on GitHub by starring the repository, reporting issues, or contributing to an issue.