Journey from Mongoose to Prisma ORM for MongoDB!
Somsubhra Das
Posted on July 29, 2021
Prisma is a next Generation ORM for NodeJS & TypeScript Environments. It has multiple databases support such as MySQL, SQLite, PostgreSQL, MSSQL and also MongoDB.
So in this post let's talk about the all new Prisma MongoDB Connector, it's operations and what made me switch from Mongoose to Prisma for MongoDB.
Connection
Let's start by establishing the connection to our MongoDB Server. In your Prisma schema file we need to change the provider
.
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
The prisma.schema
file allows us to specify how we want Prisma to connect to our database. We need to tell it what kind of provider we would like to use - in this case mongodb
- and a url
to connect to - this is pointing to an environment variable as we want to keep it secret. We will use a MongoDB connection string as the DATABASE_URL
which can be found in the /prisma/.env
file.
Next we need to setup the generator block like below.
generator client {
provider = "prisma-client-js"
previewFeatures = ["mongoDb"]
}
Since Prisma MongoDB Connector is still in preview we need to explicitly specify the previewFeatures
key.
Defining Models
So now that connection has been successfully established to MongoDB Server, let's now create models for our database collection.
A typical MongoDB document looks like this:
{
"_id": { "$oid": "60d599cb001ef98000f2cad2" },
"email": "somsubhra@email.com",
"name": "Somsubhra",
}
So now how to define a model like this in Prisma? Inside Prisma schema file, we can define our models.
model User {
id String @id @default(dbgenerated()) @map("_id") @db.ObjectId
email String @unique
name String?
posts Post[]
}
model Post {
id String @id @default(dbgenerated()) @map("_id")
published Boolean @default(false)
title String
user User? @relation(fields: [userId], references: [id])
userId String?
}
Comparing it with mongoose models, in Mongoose ODM we would have written something like:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: String,
email: {
type: String,
unique: true,
},
});
module.exports = User = mongoose.model("user", UserSchema);
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const PostSchema = new Schema({
title: String,
user: {
type: mongoose.Types.ObjectId,
ref: "user",
},
published: {
type: Boolean
default: false,
},
});
module.exports = Post = mongoose.model("post", PostSchema);
In Prisma we may also generate ObjectIds manually by using the bson
package.
import { ObjectId } from "bson";
const id = new ObjectId();
Queries & Database Operations
Now let's understand how to write queries and operations to MongoDB using Prisma in comparison to Mongoose.
Fetching Single record
Fetching a single record in prisma is done using the where
property but in mongoose it has findById
method.
Prisma
const user = await prisma.user.findUnique({
where: {
id: ObjectId('5eb9354624286a04e42401d8'),
},
})
Mongoose
const result = await User.findById('5eb9354624286a04e42401d8')
Fetching selected values for single record
Fetching selected values for single record is easier than ever in Prisma ORM by using just a single query function to do the select operation whereas in Mongoose after finding the record we need to chain the output with select()
. This increases the time complexity and also slows down the process.
Prisma
const user = await prisma.user.findUnique({
where: {
id: ObjectId('5eb9354624286a04e42401d8'),
},
select: {
name: true,
},
})
Mongoose
const user = await User.findById('5eb9354624286a04e42401d8').select(['name', 'email'])
Fetching relations
In Prisma, we use the include
property but in Mongoose we would have to use the populate()
method.
Prisma
const posts = await prisma.user.findUnique({
where: {
id: ObjectId('5eb9354624286a04e42401d8'),
},
include: {
post: true,
},
})
Mongoose
const userWithPosts = await User.findById(id).populate('posts')
Filtering with values
In Prisma we filter records using the where
property whereas in Mongoose we use the find()
.
Prisma
const posts = await prisma.post.findMany({
where: {
title: {
contains: 'Hello World',
},
},
})
Mongoose
const post = await Post.find({
title: 'Hello World',
})
Relation Filtering
Prisma
Prisma can filter a list based on a criteria that applies not only to the models of the list being retrieved, but to a relation of that model.
const posts = await prisma.user.findMany({
where: {
posts: {
some: {
title: {
contains: 'Hello',
},
},
},
},
})
Mongoose
Mongoose doesn't offer this feature for relation filters. We may achieve similar functionality by adding an additional step to filter the results returned by the query but that would result in increased query times and load for large databases.
Pagination
Prisma
Cursor-style pagination:
const page = prisma.post.findMany({
before: {
id: ObjectId('6eb93546f4w5486a04e42401d8'),
},
last: 20,
})
Offset pagination:
const cc = prisma.post.findMany({
skip: 200,
first: 20,
})
Mongoose
Mongoose also has similar implementation for pagination.
const posts = await Post.find({
skip: 5,
limit: 10,
})
Creating Records
Prisma
const user = await prisma.user.create({
data: {
email: 'user@email.com',
},
})
Mongoose
const user = await User.create({
name: 'John',
email: 'user@email.com',
})
Updating Records
Prisma updates the record directly with the values passed in data property in comparison with mongoose where we need to use $set
operator.
Prisma
const user = await prisma.user.update({
data: {
name: 'John',
},
where: {
id: ObjectId('5eb9354624286a04e42401d8'),
},
})
Mongoose
const updatedUser = await User.findOneAndUpdate(
{ _id: id },
{
$set: {
name: 'John',
},
}
)
Deleting Single Record
Prisma
const user = await prisma.user.delete({
where: {
id: ObjectId('5eb9354624286a04e42401d8'),
},
})
Mongoose
await User.findByIdAndDelete(id)
Deleting Multiple Records
Prisma
const users = await prisma.user.deleteMany({
where: {
id: {
in: [1, 2, 6, 34],
},
},
})
Mongoose
await User.deleteMany({ _id: { $in: [1, 2, 6, 34] } })
Advantages of Prisma over Mongoose
So now that we know the differences in operations between Prisma & Mongoose, let's now focus on the advantages Prisma provides over Mongoose.
- Prisma allows TypeSafe Database access.
- Prisma has an auto generated query builder
- Support for multiple databases. This is a huge advantage to developers when moving between SQL and NoSQL Databases, since only the Schema file needs to be changed. All other operations/queries remain same.
- Supports multiple RDBMS
- Prisma lets you filter a list based on a criteria that applies not only to the models of the list being retrieved, but to a relation of that model. Mongoose doesn't offer a dedicated API for relation filters. You can get similar functionality by adding an additional step to filter the results returned by the query.
- Prisma Studio tool that helps to manage data easily.
Disadvantages of Prisma
On the other side, Prisma has a few disadvantages over Mongoose as well.
- Support for multiple model files not available. All models need to be written in
schema.prisma
file which makes the file cluttered and hard to debug and read. - Prisma MongoDB support is currently in preview
- Currently no embedded collection support.
- Error handling is incomplete.
- The Migrate and Introspection workflows are currently not supported.
-
@@id
and auto-increment are not currently supported.
Should you be using Prisma over Mongoose?
Prisma is a modern ORM which has its own tradeoffs. If you are building a server side application with REST APIs and GraphQL, Prisma would be a great choice. It also makes lives of developers easier. Prisma gives a significant productivity boost for the most common database workflows.
If these factors don't matter much to you and you want to have more control over database operations then my suggestion will be to go with Mongoose "for the time being".
Contribute to Prisma
Prisma MongoDB Connector is still in preview and development. If you want to contribute to the Prisma check out their GitHub Repository by clicking here.
Posted on July 29, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.