CHAPTER 4Prisma Client
Prisma Client is a generated library specific for your database schema. With this client library, you can do all possible operations to your database with the comfort of autocompletion by Typescript.
Generation
To generate the Prisma Schema you must invoke the prisma
CLI with the generate
subcommand:
bunx prisma generate
This will generate the source code for the @prisma/client
package, which will be exactly adapted to the schema you provided (Typescript types and all).
Usage
Import PrismaClient
and instantiate a global object:
import { PrismaClient } from "@prisma/client";
export default new PrismaClient();
or, equivalently
import { PrismaClient } from "@prisma/client";
export const db = new PrismaClient();
Every entity defined in the schema appears as a field of the client, so if a model called User
exists, the prisma.user
field will represent the table/collection of entities.
CRUD Operations
Every field of prisma
representing a collection has the following methods:
findFirst | First entity satisfying a condition |
findFirstOrThrow | Throwing version of |
findUnique | Single entity (only if |
findUniqueOrThrow | Throwing version of |
findMany | All entities satisfying a condition |
create | Create an entity |
createMany | Create many entities |
update | Update an entity |
updateMany | Update many entites satisfying a condition |
upsert | Update or insert if it doesn't exist |
delete | Delete an entity |
deleteMany | Delete many entities satisfying a condition |
Schema for examples
The following schema is assumed in all the examples given afterwards:
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
profileViews Int @default(0)
role Role @default(USER)
coinflips Boolean[]
posts Post[]
city String
country String
profile ExtendedProfile?
pets Json
}
model ExtendedProfile {
id Int @id @default(autoincrement())
userId Int? @unique
bio String?
User User? @relation(fields: [userId], references: [id])
}
model Post {
id Int @id @default(autoincrement())
title String
published Boolean @default(true)
author User @relation(fields: [authorId], references: [id])
authorId Int
comments Json
views Int @default(0)
likes Int @default(0)
}
enum Role {
USER
ADMIN
}
Create
Create a new user:
const user = await prisma.user.create({
data: { email: "alice@prisma.io" },
});
Create many users:
const user = await prisma.user.createMany({
data: [{ email: "alice@prisma.io" }, { email: "bob@prisma.io" }],
});
Update
Update a user:
const user = await prisma.user.update({
where: { id: 1 },
data: { email: "bob@prisma.io" },
});
Upsert
Upsert an admin user with email
alice@prisma.io
or create if it doesn't exist:
const user = await prisma.user.upsert({
where: { email: "alice@prisma.io" },
update: { role: "ADMIN" },
create: {
role: "ADMIN",
email: "alice@prisma.io",
},
});
Queries
Find the user with email
of alice@prisma.io
:
await prisma.user.findUnique({
where: { email: { equals: "alice@prisma.io" } },
});
Find the user with id
42 (equals
not necessary):
await prisma.user.findUnique({ where: { id: 42 } });
Find all users with name
Alice:
await prisma.user.findMany({ where: { name: "Alice" } });
Find a post with title
starting with "A test":
await prisma.post.create({ data: { title: "A test 1" } });
await prisma.post.create({ data: { title: "A test 2" } });
await prisma.post.findFirst({
where: { title: { startsWith: "A test" } },
orderBy: { title: "asc" },
take: -1, // Start from the end and take 1
});
Options object
CRUD methods all receive an options method of a certain type (depending on the operation).
where | The filter, a condition that entities must satisfy |
select | Which fields that should be included in the result |
take | How many entities should be returned |
skip | How many entities to skip in the result |
include | Which relationships should be eagerly loaded |
orderBy | The order of the result |
distinct | Filter out duplicate rows by field |
Filter operators
equals | { name: { equals: 'Jose' } } |
{ name: 'Jose' } | |
not | { name: { not: 'Jose' } } |
in | { name: { in: ['Groucho', 'Chicco', 'Harpo'] } } |
notIn | { id: { notIn: [22, 91, 14, 2, 5] } } |
lt | { likes: { lt: 9 } } |
lte | { likes: { lte: 9 } } |
gt | { likes: { gt: 9 } } |
gte | { likes: { gte: 9 } } |
contains | { text: { contains: 'fullstack' } } |
search | { title: { search: 'frontend & backend' } } |
startsWith | { title: { startsWith: 'The' } } |
endsWith | { email: { endsWith: '@proton.me' } } |
AND | { AND: [{ name: 'Jose' }, { age: 35 }] } |
OR | { OR: [{ name: 'Jose' }, { name: 'Pau' }] } |
NOT | { NOT: { name: 'Jose' } } |
Relations
The include
option specifies which related entities should be populated:
const users = await prisma.user.findMany({
include: {
posts: true,
profile: true,
},
});
Filters also can affect relations:
some | Some related entities satisfy condition |
every | Every related entity satisfies condition |
none | No related entities satisfy condition |
is | Populate with related entities satisfying filter |
isNot | Populate with related entities NOT satisfying filter |
Aggregation
Some methods of a table/collection can compute aggregate results, count or group by certain fields:
count | Count entities satisfying a condition |
aggregate | Count entities satisfying a condition |
groupBy | Count entities satisfying a condition |
Count
The count
method can compute counts of entites satisfying a certain condition:
// Count all users
const nusers = await prisma.user.count();
// Count users with a post published
const onePub = await prisma.user.count({
where: {
post: {
some: { published: true },
},
},
});
Aggregate
The aggregate
method can compute many aggregation statistics at once:
const minMaxAge = await prisma.user.aggregate({
_count: {
_all: true,
},
_max: {
profileViews: true,
},
_min: {
profileViews: true,
},
});
GroupBy
The groupBy
method can group entities by some fields, and then do aggregations on them:
const groupUsers = await prisma.user.groupBy({
by: ["country", "city"],
_count: { _all: true, city: true },
_sum: { profileViews: true },
orderBy: { country: "desc" },
having: { profileViews: { _avg: { gt: 200 } } },
});