Query Operations
In lieu of more extensive documentation, this page documents query operations on the prisma client such as creating, finding, updating and deleting records.
Schema
The examples use the following prisma schema models:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
name String
points Float @default(0)
meta Json @default("{}")
emails String[]
posts Post[]
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [user_id], references: [id])
user_id String @unique
bio String
image Bytes?
}
model Post {
id String @id @default(cuid())
created_at DateTime @default(now())
updated_at DateTime @updatedAt
title String
published Boolean
views Int @default(0)
desc String?
author User? @relation(fields: [author_id], references: [id])
author_id String?
categories Category[] @relation(references: [id])
}
model Category {
id Int @id @default(autoincrement())
posts Post[] @relation(references: [id])
name String
}
Creating
Single Record
user = await client.user.create(
data={
'name': 'Robert',
},
)
Many Records
Warning
create_many is not available for SQLite
users = await client.user.create_many(
data=[
{'name': 'Tegan'},
{'name': 'Alfie'},
{'name': 'Robert'},
]
)
users = await client.user.create_many(
data=[
{'id': 'abc', 'name': 'Tegan'},
{'id': 'def', 'name': 'Alfie'},
{'id': 'ghi', 'name': 'Robert'},
],
skip_duplicates=True,
)
Relational Records
user = await client.user.create(
data={
'name': 'Robert',
'profile': {
'create': {
'bio': 'My very cool bio!',
}
}
}
)
user = await client.user.create(
data={
'name': 'Robert',
'posts': {
'create': [
{
'title': 'My first post!',
'published': True,
},
{
'title': 'My draft post!',
'published': False,
},
]
}
}
)
Finding
Unique Records
user = await client.user.find_unique(
where={
'id': '1',
}
)
user = await client.user.find_unique(
where={
'id': '2',
},
include={
'posts': True,
},
)
A Single Record
post = await client.post.find_first(
where={
'title': {'contains': 'Post'},
},
)
post = await client.post.find_first(
skip=2,
where={
'title': {
'contains': 'Post'
},
},
cursor={
'id': 'abcd',
},
include={
'author': True,
},
order={
'id': 'asc',
}
)
Multiple Records
posts = await client.post.find_many(
where={
'published': True,
},
)
posts = await client.post.find_many(
take=5,
skip=1,
where={
'published': True,
},
cursor={
'id': 'desc',
},
include={
'categories': True,
},
order={
'id': 'desc',
}
)
Filtering by Relational Fields
Within the filter you can query for everything you would normally query for, like it was a find_first() call on the relational field, for example:
post = await client.post.find_first(
where={
'author': {
'is': {
'name': 'Robert',
},
},
},
)
user = await client.user.find_first(
where={
'name': 'Robert',
},
)
One to One
post = await client.post.find_first(
where={
'author': {
'is': {
'name': 'Robert',
},
'is_not': {
'name': 'Tegan',
},
},
},
)
One to Many
Excluding
post = await client.post.find_first(
where={
'categories': {
'none': {
'name': 'Exclude Category',
},
},
},
)
At Least One
post = await client.post.find_first(
where={
'categories': {
'some': {
'name': {
'contains': 'Special',
},
},
},
},
)
Every
post = await client.post.find_first(
where={
'categories': {
'every': {
'name': {
'contains': 'Category',
},
},
},
},
)
Filtering by Field Values
Note
The examples for filtering fields are simply to showcase possible arguments, all the arguments passed together will result in either an invalid query or no records being found.
String Fields
Warning
Case insensitive filtering is only available on PostgreSQL and MongoDB
post = await client.post.find_first(
where={
'desc': 'Must be exact match',
# or
'desc': {
'equals': 'example_string',
'not_in': ['ignore_string_1', 'ignore_string_2'],
'lt': 'z',
'lte': 'y',
'gt': 'a',
'gte': 'b',
'contains': 'string must be present',
'startswith': 'must start with string',
'endswith': 'must end with string',
'in': ['find_string_1', 'find_string_2'],
'mode': 'insensitive',
'not': {
# recursive type
'contains': 'string must not be present',
'mode': 'default',
...
},
},
},
)
Integer Fields
post = await client.post.find_first(
where={
'views': 10,
# or
'views': {
'equals': 1,
'in': [1, 2, 3],
'not_in': [4, 5, 6],
'lt': 10,
'lte': 9,
'gt': 0,
'gte': 1,
'not': {
# recursive type
'gt': 10,
...
},
},
},
)
Float Fields
user = await client.user.find_first(
where={
'points': 10.0,
# or
'points': {
'equals': 10.0,
'in': [1.2, 1.3, 1.4],
'not_in': [4.7, 53.4, 6.8],
'lt': 100.5,
'lte': 9.9,
'gt': 0.0,
'gte': 1.2,
'not': {
# recursive type
'gt': 10.0,
...
},
},
},
)
DateTime Fields
from datetime import datetime
post = await client.post.find_first(
where={
'updated_at': datetime.now(),
# or
'updated_at': {
'equals': datetime.now(),
'not_in': [datetime.now(), datetime.utcnow()],
'lt': datetime.now(),
'lte': datetime.now(),
'gt': datetime.now(),
'gte': datetime.now(),
'in': [datetime.now(), datetime.utcnow()],
'not': {
# recursive type
'equals': datetime.now(),
...
},
},
},
)
Boolean Fields
post = await client.post.find_first(
where={
'published': True,
# or
'published': {
'equals': True,
'not': False,
},
},
)
Json Fields
Note
Json fields must match exactly.
Warning
Json fields are not supported on SQLite
from prisma import Json
user = await client.user.find_first(
where={
'meta': Json({'country': 'Scotland'})
# or
'meta': {
'equals': Json.keys(country='Scotland'),
'not': Json(['foo']),
}
}
)
Bytes Fields
Note
Bytes fields are encoded to and from Base64
from prisma import Base64
profile = await client.profile.find_first(
where={
'image': Base64.encode(b'my binary data'),
# or
'image': {
'equals': Base64.encode(b'my binary data'),
'not': Base64(b'WW91IGZvdW5kIGFuIGVhc3RlciBlZ2chIExldCBAUm9iZXJ0Q3JhaWdpZSBrbm93IDop'),
},
},
)
Lists fields
Warning
Scalar list fields are only supported on PostgreSQL and MongoDB
Every scalar type can also be defined as a list, for example:
user = await client.user.find_first(
where={
'emails': {
# only one of the following fields is allowed at the same time
'has': 'robert@craigie.dev',
'has_every': ['email1', 'email2'],
'has_some': ['email3', 'email4'],
'is_empty': True,
},
},
)
Combining arguments
All of the above mentioned filters can be combined with other filters using AND, NOT and OR.
AND
The following query will return the first post where the title contains the words prisma and test.
post = await client.post.find_first(
where={
'AND': [
{
'title': {
'contains': 'prisma',
},
},
{
'title': {
'contains': 'test',
},
},
],
},
)
OR
The following query will return the first post where the title contains the word prisma or is published.
post = await client.post.find_first(
where={
'OR': [
{
'title': {
'contains': 'prisma',
},
},
{
'published': True,
},
],
},
)
NOT
The following query will return the first post where the title is not My test post
post = await client.post.find_first(
where={
'NOT' [
{
'title': 'My test post',
},
],
},
)
Deleting
Unique Record
post = await client.post.delete(
where={
'id': 'cksc9m7un0028f08zwycxtjr1',
},
)
post = await client.post.delete(
where={
'id': 'cksc9m1vu0021f08zq0066pnz',
},
include={
'categories': True,
}
)
Multiple Records
total = await client.post.delete_many(
where={
'published': False,
}
)
Updating
Unique Record
post = await client.post.update(
where={
'id': 'cksc9lp7w0014f08zdkz0mdnn',
},
data={
'views': {
'increment': 1,
}
},
include={
'categories': True,
}
)
Multiple Records
total = await client.post.update_many(
where={
'published': False
},
data={
'views': 0,
},
)
Creating On Not Found
post = await client.post.upsert(
where={
'id': 'cksc9ld4z0007f08z7obo806s',
},
data={
'create': {
'title': 'This post was created!',
'published': False,
}
'update': {
'title': 'This post was updated',
'published': True,
},
},
include={
'categories': True,
}
)
Updating Atomic Fields
If a field is an int or float type then it can be atomically updated, i.e. mathematical operations can be applied without knowledge of the previous value.
Integer Fields
post = await client.post.update(
where={
'id': 'abc',
},
data={
'views': 1,
# or
'views': {
'set': 5,
'increment': 1,
'decrement': 2,
'multiply': 5,
'divide': 10,
},
},
)
Float Fields
user = await client.user.update(
where={
'id': 'abc',
},
data={
'points': 1.0,
# or
'points': {
'set': 1.0,
'increment': 1.5,
'decrement': 0.5,
'multiply': 2.5,
'divide': 3.0,
},
},
)
Updating List Fields
Warning
Scalar list fields are only supported on PostgreSQL and MongoDB
user = await client.user.update(
where={
'id': 'cksc9lp7w0014f08zdkz0mdnn',
},
data={
'email': {
'set': ['robert@craigie.dev', 'robert@example.com'],
# or
'push': ['robert@example.com'],
},
}
)
Aggregrating
Counting Records
total = await client.post.count(
where={
'published': True,
},
)
total = await client.post.count(
take=10,
skip=1,
where={
'published': True,
},
cursor={
'id': 'cksca3xm80035f08zjonuubik',
},
order={
'created_at': 'asc',
},
)
Batching Write Queries
async with client.batch_() as batcher:
batcher.user.create({'name': 'Robert'})
batcher.user.create({'name': 'Tegan'})
Raw Queries
Note
SQL queries are sent directly to the database so you must use the syntax for your specific database provider
Warning
Raw query results are raw dictionaries unless the model argument is specified
Write Queries
total = await client.execute_raw(
'''
SELECT *
FROM User
WHERE User.id = ?
''',
'cksca3xm80035f08zjonuubik'
)
Selecting Multiple Records
posts = await client.query_raw(
'''
SELECT *
FROM Post
WHERE Post.published IS TRUE
'''
)
Type Safety
from prisma.models import Post
posts = await client.query_raw(
'''
SELECT *
FROM Post
WHERE Post.published IS TRUE
''',
model=Post,
)
Selecting a Single Record
post = await client.query_first(
'''
SELECT *
FROM Post
WHERE Post.published IS TRUE
LIMIT 1
'''
)
Type Safety
from prisma.models import Post
post = await client.query_first(
'''
SELECT *
FROM Post
WHERE Post.views > 50
LIMIT 1
''',
model=Post
)