Type Safety With Prisma & MongoDB
Rate this tutorial
Did you know that Prisma now supports MongoDB? In this article, we'll take a look at how to use Prisma to connect to MongoDB.
Prisma is an open source ORM (Object Relational Mapper) for Node.js. It supports both JavaScript and TypeScript. It really shines when using TypeScript, helping you to write code that is both readable and type-safe.
If you want to hear from Nikolas Burk and Matthew Meuller of Prisma, check out this episode of the MongoDB Podcast.
Schemas help developers avoid data inconsistency issues over time. While you can define a schema at the database level within MongoDB, Prisma lets you define a schema at the application level. When using the Prisma Client, a developer gets the aid of auto-completing queries, since the Prisma Client is aware of the schema.
Generally, data that is accessed together should be stored together in a MongoDB database. Prisma supports using embedded documents to keep data together.
However, there may be use cases where you'll need to store related data in separate collections. To do that in MongoDB, you can include one document’s
_id
field in another document. In this instance, Prisma can assist you in organizing this related data and maintaining referential integrity of the data.We are going to take an existing example project from Prisma’s
prisma-examples
repository.One of the examples is a blog content management platform. This example uses a SQLite database. We'll convert it to use MongoDB and then seed some dummy data.
In this article, we’ll use a MongoDB Atlas cluster. To create a free account and your first forever-free cluster, follow the Get Started with Atlas guide.
We'll first need to set up our environment variable to connect to our MongoDB Atlas database. I'll add my MongoDB Atlas connection string to a
.env
file.Example:
1 DATABASE_URL="mongodb+srv://<username>:<password>@<cluster>.mongodb.net/prisma?retryWrites=true&w=majority"
You can get your connection string from the Atlas dashboard.
Now, let's edit the
schema.prisma
file.If you are using Visual Studio Code, be sure to install the official Prisma VS Code extension to help with formatting and auto-completion.
While you’re in VS Code, also install the official MongoDB VS Code extension to monitor your database right inside VS Code!
In the
datasource db
object, we'll set the provider to "mongodb" and the url to our environment variable DATABASE_URL
.For the
User
model, we'll need to update the id
. Instead of an Int
, we'll use String
. We'll set the default to auto()
. Since MongoDB names the id
field _id
, we'll map the id
field to _id
. Lastly, we'll tell Prisma to use the data type of ObjectId
for the id
field.We'll do the same for the
Post
model id
field. We'll also change the authorId
field to String
and set the data type to ObjectId
.1 generator client { 2 provider = "prisma-client-js" 3 } 4 5 datasource db { 6 provider = "mongodb" 7 url = env("DATABASE_URL") 8 } 9 10 model User { 11 id String @id @default(auto()) @map("_id") @db.ObjectId 12 email String @unique 13 name String? 14 posts Post[] 15 } 16 17 model Post { 18 id String @id @default(auto()) @map("_id") @db.ObjectId 19 createdAt DateTime @default(now()) 20 updatedAt DateTime @updatedAt 21 title String 22 content String? 23 published Boolean @default(false) 24 viewCount Int @default(0) 25 author User @relation(fields: [authorId], references: [id]) 26 authorId String @db.ObjectId 27 }
This schema will result in a separate
User
and Post
collection in MongoDB. Each post will have a reference to a user.Now that we have our schema set up, let's install our dependencies and generate our schema.
1 npm install 2 npx prisma generate
If you make any changes later to the schema, you'll need to run
npx prisma generate
again.Next, we need to seed our database. The repo comes with a
prisma/seed.ts
file with some dummy data.So, let's run the following command to seed our database:
1 npx prisma db seed
This also creates the
User
and Post
collections that are defined in prisma/schema.prisma
.Because we made some changes to the
id
data type, we'll need to update some of the example code to reflect these changes.Here's one example. We need to remove the
Number()
call from the reference to the id
field since it is now a String
.1 // BEFORE 2 async function handleGET(postId, res) { 3 const post = await prisma.post.findUnique({ 4 where: { id: Number(postId) }, 5 include: { author: true }, 6 }) 7 res.json(post) 8 } 9 10 // AFTER 11 async function handleGET(postId, res) { 12 const post = await prisma.post.findUnique({ 13 where: { id: postId }, 14 include: { author: true }, 15 }) 16 res.json(post) 17 }
Notice in this file, when hovering over the
post
variable, VS Code knows that it is of type Post
. If we just wanted a specific field from this, VS Code automatically knows which fields are included. No guessing!Those are all of the updates needed. We can now run the app and we should see the seed data show up.
1 npm run dev
We can open the app in the browser at
http://localhost:3000/
.From the main page, you can click on a post to see it. From there, you can delete the post.
We can go to the Drafts page to see any unpublished posts. When we click on any unpublished post, we can publish it or delete it.
The "Signup" button will allow us to add a new user to the database.
And, lastly, we can create a new post by clicking the "Create draft" button.
All of these actions are performed by the Prisma client using the API routes defined in our application.
Prisma makes dealing with schemas in MongoDB a breeze. It especially shines when using TypeScript by making your code readable and type-safe. It also helps to manage multiple collection relationships by aiding with referential integrity.
I can see the benefit of defining your schema at the application level and will be using Prisma to connect to MongoDB in the future.