Queries
Overview
How are queries in the Prisma API generated?
The GraphQL API of a Prisma service is specified in the Prisma GraphQL schema. The Prisma GraphQL schema is auto-generated based on the service's datamodel:
The Query
type of the Prisma GraphQL schema defines all the queries the Prisma API accepts.
As an example, consider the following datamodel:
type User {
id: ID! @unique
name: String!
}
This is the Query
type Prisma will generate:
type Query {
users(
where: UserWhereInput
orderBy: UserOrderByInput
skip: Int
after: String
before: String
first: Int
last: Int
): [User]!
user(where: UserWhereUniqueInput!): User
usersConnection(
where: UserWhereInput
orderBy: UserOrderByInput
skip: Int
after: String
before: String
first: Int
last: Int
): UserConnection!
}
For every type in your datamodel, three queries are generated. Taking above the above User
type as an example, these queries are:
user
: Retrieve a singleUser
nodeusers
: Retrieve a list ofUser
nodes (as an object query)usersConnection
: Retrieve a list ofUser
nodes (as a connection query)
To inspect all the available operations of your Prisma API in detail, you can read the Prisma GraphQL schema of your Prisma service. It can be downloaded with the GraphQL CLI:
graphql get-schema --endpoint __YOUR_PRISMA_ENDPOINT__ --output prisma.graphql --no-all
Another way to learn about the concrete capabilities of your Prisma API is by exploring the auto-generated API documentation inside a GraphQL Playground. You can do so by clicking the green SCHEMA-button at the right edge of the Playground:
Datamodel for examples on this page
All example queries on this page are based on a Prisma service configured with this datamodel:
type Post {
id: ID! @unique
title: String!
published: Boolean!
author: User!
}
type User {
id: ID! @unique
age: Int
email: String! @unique
name: String!
accessRole: AccessRole
posts: [Post!]!
}
enum AccessRole {
USER
ADMIN
}
Query concepts
The Prisma API offers two kinds of queries:
- Object queries: Fetch single or multiple nodes of a certain object type.
- Connection queries: Expose advanced features like aggregations and Relay compliant connections enabling a powerful pagination model.
When working with the Prisma API, the following concepts are also useful to keep in mind:
- Hierarchical (or nested) queries: Fetch data across relations.
- Query arguments: Allow for filtering, sorting, pagination and more.
Object queries
We can use object queries to fetch either a single node, or a list of nodes for a certain object type.
Here, we use the posts
query to fetch a list of Post
nodes. In the response, we include only the id
and title
of each Post
node:
query {
posts {
id
title
}
}
We can also query a specific Post
node using the post
query. Note that we're using the where
argument to select the node:
query {
post(where: { id: "cixnen24p33lo0143bexvr52n" }) {
id
title
published
}
}
Because User
is another type in our datamodel, users
is another available query. Again, we can use the where
argument to specify conditions for the returned users. In this example, we filter for all User
nodes that have their age
higher than 18
:
query {
users(where: { age_gt: 18 }) {
id
name
}
}
This also works across relations. Here we're fetching those Post
nodes that have an author
with the age
higher than 18
:
query {
posts(where: { author: { age_gt: 18 } }) {
id
title
author {
name
age
}
}
}
You can read more about node selection here.
Connection queries
Object queries directly return a list of nodes. In special cases, or when using advanced features, using connection queries is the preferred option. They are an extension of (and fully compliant with) Relay connections.
The core idea of Relay connections is to provide meta-information about the edges in the data graph. For example, each edge not only has access to information about the corresponding object (the node
) but also is associated with a cursor
that allows to implement powerful, cursor-based pagination.
Here, we fetch all Post
nodes using the postsConnection
query. Notice that we're also asking for the cursor
of each edge:
# Fetch all posts
query {
postsConnection {
edges {
cursor
node {
id
title
}
}
}
}
Connection queries also expose aggregation features via the aggregate
field:
# Count all posts with a title containing 'GraphQL'
query {
postsConnection(where: { title_contains: "GraphQL" }) {
aggregate {
count
}
}
}
More aggregations will be added over time. Find more information about the roadmap here.
Querying data across relations
Every available relation in your datamodel adds a new field to the queries of the two models it connects.
Here, we are fetching a specific User
node, and all its related Post
nodes using the posts
field:
query {
user(where: { id: "cixnekqnu2ify0134ekw4pox8" }) {
id
name
posts {
id
published
}
}
}
user.posts
acts exactly like the top-level posts
query in that it lets you specify which fields of the Post
type you're interested in.
Query arguments
Throughout the Prisma API, you'll find query arguments that you can provide to further control the query response. It can be either of the following:
- Ordering: Sorting nodes by any field value using
orderBy
- Filtering: Selecting nodes in a query by scalar or relational filters using
where
- Pagination: Slicing nodes in a query using
first
andbefore
,last
andafter
, andskip
These query arguments can be combined to achieve very specific query responses.
Ordering
When querying all nodes of a type you can supply the orderBy
argument for every scalar field of the type: orderBy: <field>_ASC
or orderBy: <field>_DESC
.
Order the list of all Post
nodes ascending by title
:
query {
posts(orderBy: title_ASC) {
id
title
published
}
}
Order the list of all Post
nodes descending by published
:
query {
posts(orderBy: published_DESC) {
id
title
published
}
}
The field you are ordering by does not have to be selected in the actual query. If you do not specify an ordering, the response is automatically ordered ascending by the id
field.
It's currently not possible to order responses by multiple fields or by related fields. Join the discussion in the feature requests if you're interested in these features!
Filtering
When querying all nodes of a type you can supply different parameters to the where
argument to constrain the data in the response according to your requirements. The available options depend on the scalar and relational fields defined on the type in question.
Applying single filters
If you supply exactly one parameter to the where
argument, the query response will only contain nodes that adhere to this constraint. Multiple filters can be combined using AND
and/or OR
, see below for more.
Filtering by a concrete value
The easiest way to filter a query response is by supplying a concrete value for a certain field to filter by.
Query all Post
nodes that are not yet published
:
query {
posts(where: { published: false }) {
id
title
published
}
}
Query all User
nodes with a specific name
:
query {
users(where: { name: "Alice" }) {
id
}
}
Query all User
nodes with a specific age
:
query {
users(where: { age: 30 }) {
id
}
}
Advanced filter criteria
Depending on the type of the field you want to filter by, you have access to different advanced criteria you can use to filter your query response.
Query all Post
nodes whose title
is in a given list of strings:
query {
posts(where: { title_in: ["My biggest Adventure", "My latest Hobbies"] }) {
id
title
published
}
}
Query all User
nodes whose age
is less than 42:
query {
users(where: { age_lt: 42 }) {
id
}
}
Relation filters
For to-one relations, you can define conditions on the related node by nesting the according argument in where
.
Query all Post
nodes where the author
has the USER
access role:
query {
posts(where: { author: { accessRole: USER } }) {
title
}
}
For to-many relations, three additional arguments are available: every
, some
and none
, to define that a condition should match every
, some
or none
related nodes.
Query all User
nodes that have at least one Post
node that's published
:
query {
users(where: { posts_some: { published: true } }) {
id
posts {
published
}
}
}
Relation filters are also available in the nested arguments for to-one or to-many relations.
Query all User
nodes that did not like a Post
of an author
in the ADMIN
access role:
query {
users(where: { likedPosts_none: { author: { accessRole: ADMIN } } }) {
name
}
}
likedPosts
is not part of the above mentioned datamodel but can easily be added by adding the corresponding field to theUser
type:likedPosts: [Post!]! @relation(name: "LikedPosts")
. We also provide aname
for the relation to resolve the ambiguity we would otherwise create because there are two relation fields targettingPost
on theUser
type.
Combining multiple filters
You can use the filter combinators OR
, AND
and NOT
to create an arbitrary logical combination of filter conditions:
- For an
AND
-filter to evaluate totrue
, all of the nested conditions have to betrue
. - For an
OR
-filter to evaluate totrue
, at least one of the nested conditions has to betrue
. - For a
NOT
-filter to evaluate totrue
, all of the nested conditions have to befalse
.
Using OR
, AND
and NOT
Let's start with an easy example:
Query all Post
nodes that are published
and whose title
is in a given list of strings:
query {
posts(
where: {
AND: [
{ title_in: ["My biggest Adventure", "My latest Hobbies"] }
{ published: true }
]
}
) {
id
title
published
}
}
OR
, AND
and NOT
each accept a list as input where each list item is an object and therefore needs to be wrapped with curly braces. The sample filter condition from the above query contains two filter objects:
{title_in: ["My biggest Adventure", "My latest Hobbies"]}
{published: true}
Only if both filter conditions are true for a Post
node, that node will be included in the response.
Arbitrary combination of filters with AND
, OR
and NOT
You can combine and even nest the filter combinators AND
, OR
and NOT
to create arbitrary logical combinations of filter conditions.
Query all Post
nodes that are either published
and whose title
is in a list of given strings, or have the specific id
we supply:
query {
posts(
where: {
OR: [
{
AND: [
{ title_in: ["My biggest Adventure", "My latest Hobbies"] }
{ published: true }
]
}
{ id: "cixnen24p33lo0143bexvr52n" }
]
}
) {
id
title
published
}
}
Notice how we nest the AND
combinator inside the OR
combinator.
Limitations
Currently, neither scalar list filters nor JSON filters are available. Join the discussion in the respective feature requests on GitHub.
Pagination
When querying all nodes of a specific object type, you can supply arguments that allow you to paginate the query response.
Seeking forward and backward with first
and last
Pagination allows you to request a certain chunk of nodes. You can seek forwards or backwards through the nodes and supply an optional starting node:
- To seek forward, use
first
; specify a starting node withafter
. - To seek backward, use
last
; specify a starting node withbefore
.
You cannot combine first
with before
or last
with after
. If you do so in a query, before
or after
will simply be ignored and only first
or last
is applied (at the very beginning or end of the list, depending on which you're using).
Note that you can query for more nodes than exist without an error message.
Skipping elements with skip
You can also skip an arbitrary amount of nodes in whichever direction you are seeking by supplying the skip
argument:
- When using
first
,skip
skips elements at the beginning of the list - When using
last
,skip
skips elements from the end of the list
Examples
For the following examples, we're assuming a list of exactly 30 nodes:
Query the first 3 nodes (seeking forward):
query {
posts(first: 3) {
id
title
}
}
Query the nodes from position 6 to position 10 (seeking forward):
query {
posts(first: 5, skip: 5) {
id
title
}
}
Query the last 3 nodes (seeking backward):
query {
posts(last: 3) {
id
title
}
}
Query the nodes from position 21 to position 27 (seeking backward):
query {
posts(last: 7, skip: 3) {
id
title
}
}
Query the first 3 nodes after the node with cixnen24p33lo0143bexvr52n
as id
:
query {
posts(first: 3, after: "cixnen24p33lo0143bexvr52n") {
id
title
}
}
Query the first 5 nodes after the node with cixnen24p33lo0143bexvr52n
as id
and skipping 3 nodes:
query {
posts(first: 5, after: "cixnen24p33lo0143bexvr52n", skip: 3) {
id
title
}
}
Query the last 5 nodes before the node with cixnen24p33lo0143bexvr52n
as id
:
query {
posts(last: 5, before: "cixnen24p33lo0143bexvr52n") {
id
title
}
}
Query the last 3 nodes before the node with cixnen24p33lo0143bexvr52n
as id
and skipping 5 nodes:
query {
posts(last: 3, before: "cixnen24p33lo0143bexvr52n", skip: 5) {
id
title
}
}