Use the Json Prisma field type to read, write, and perform basic filtering on JSON types in the underlying database. In the following example, the User model has an optional Json field named extendedPetsData:

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
extendedPetsData Json?
}

Example field value:

{
"pet1": {
"petName": "Claudine",
"petType": "House cat"
},
"pet2": {
"petName": "Sunny",
"petType": "Gerbil"
}
}

Note: The Json field is only supported if the underlying database has a corresponding JSON data type.

The Json field supports a few additional types, such as string and boolean. These additional types exist to match the types supported by JSON.parse():

export declare type JsonValue = string | number | boolean | null | JsonObject | JsonArray

Use cases for JSON fields

Reasons to store data as JSON rather than representing data as related models include:

  • You need to store data that does not have a consistent structure
  • You are importing data from another system and do not want to map that data to Prisma models

Reading a Json field

You can use the Prisma.JsonArray and Prisma.JsonObject utility classes to work with the contents of a Json field:

const { PrismaClient, Prisma } = require('@prisma/client')
const user = await prisma.user.findFirst({
where: {
id: 9,
},
})
// Example extendedProfile data:
// [{ name: 'Bob the dog' }, { name: 'Claudine the cat' }]
if (user?.pets && typeof user?.pets === 'object' && Array.isArray(user?.pets)) {
const petsObject = user?.pets as Prisma.JsonArray
const firstPet = petsObject[0]
}

See also: Advanced example: Update a nested JSON key value

Writing to a Json field

The following example writes a JSON object to the extendedPetsData field:

var json = [{ name: 'Bob the dog' }, { name: 'Claudine the cat' }] as Prisma.JsonArray
const createUser = await prisma.user.create({
data: {
email: 'birgitte@prisma.io',
extendedPetsData: json,
},
})

Note: JavaScript objects (for example, { extendedPetsData: "none"}) are automatically converted to JSON.

See also: Advanced example: Update a nested JSON key value

Filtering on a Json field

Advanced Json filtering is available as a Preview feature in 2.23.0 and later. In earlier versions, you can filter on the exact Json field value.

Advanced Json filtering is supported by PostgreSQL and MySQL with different syntaxes for the path option. PostgreSQL does not support filtering on object key values in arrays.

To enable advanced filtering, add filterJson to previewFeatures in your schema:

generator client {
provider = "prisma-client-js"
previewFeatures = ["filterJson"]
}

Database connector implementation differences

The implementation of Json filtering differs between connectors:

This means that path option syntax differs between database connectors - for example, the following is a valid MySQL path value:

$petFeatures.petName

The following is a valid PostgreSQL path value:

["petFeatures", "petName"]

Filter on exact field value

The following query returns all users where the value of extendedPetsData matches the json variable exactly:

var json = { [{ name: 'Bob the dog' }, { name: 'Claudine the cat' }] }
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
equals: json,
},
},
})

The following query returns all users where the value of extendedPetsData does not match the json variable exactly:

var json = { extendedPetsData: [{ name: 'Bob the dog' }, { name: 'Claudine the cat' }] }
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
not: json,
},
},
})

Filter on object property

In 2.23.0 and later, you can filter on a specific property inside a block of JSON. In the following examples, the value of extendedPetsData is a one-dimensional, unnested JSON object:

{
"petName": "Claudine",
"petType": "House cat"
}

The following query returns all users where the value of petName is "Claudine":

PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['petName'],
equals: 'Claudine',
},
},
})

The following query returns all users where the value of petType contains '"cat"':

PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['petType'],
string_contains: 'cat',
},
},
})

The following string filters are available:

Filter on nested object property

You can filter on nested JSON properties. In the following examples, the value of extendedPetsData is a JSON object with several levels of nesting.

{
"pet1": {
"petName": "Claudine",
"petType": "House cat"
},
"pet2": {
"petName": "Sunny",
"petType": "Gerbil",
"features": {
"eyeColor": "Brown",
"furColor": "White and black"
}
}
}

The following query returns all users where "pet2" "petName" is "Sunny":

PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['pet2', 'petName'],
equals: 'Sunny',
},
},
})

The following query returns all users where:

  • "pet2" "petName" is "Sunny"
  • "pet2" "features" "furColor" contains "black"
PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
AND: [
{
extendedPetsData: {
path: ['pet2', 'petName'],
equals: 'Sunny',
},
},
{
extendedPetsData: {
path: ['pet2', 'features', 'furColor'],
string_contains: 'black',
},
},
],
},
})

Filtering on an array value

You can filter on the presence of a specific value in a scalar array (strings, integers). In the following examples, the value of extendedPetsData is an array of strings:

["Claudine", "Sunny"]

The following query returns all users with a pet named "Claudine":

PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
array_contains: ['Claudine'],
},
},
})

Note: In PostgresSQL, the value of array_contains must be an array and not a string, even if the array only contains a single value.

The following array filters are available:

Filtering on nested array value

You can filter on the presence of a specific value in a scalar array (strings, integers). In the following examples, the value of extendedPetsData includes nested scalar arrays of names:

{
"cats": { "owned": ["Bob", "Sunny"], "fostering": ["Fido"] },
"dogs": { "owned": ["Ella"], "fostering": ["Prince", "Empress"] }
}

Scalar value arrays

The following query returns all users that foster a cat named "Fido":

PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['cats', 'fostering'],
array_contains: ['Fido'],
},
},
})

Note: In PostgresSQL, the value of array_contains must be an array and not a string, even if the array only contains a single value.

The following query returns all users that foster cats named "Fido" and "Bob":

PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['cats', 'fostering'],
array_contains: ['Fido', 'Bob'],
},
},
})

JSON object arrays

PostgreSQL
MySQL
const json = [{ status: 'expired', insuranceID: 92 }]
const checkJson = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['insurances'],
array_contains: json,
},
},
})
  • If you are using PostgreSQL, you must pass in an array of objects to match, even if that array only contains one object:

    [{ "status": "expired", "insuranceID": 92 }] // PostgreSQL

    If you are using MySQL, you must pass in a single object to match:

    { "status": "expired", "insuranceID": 92 } // MySQL
  • If your array contains multiple objects, PostgreSQL will only return results if

  • You must set array_contains to a JSON object, not a string. If you use a string, Prisma escapes the quotation marks and the query will not return results. For example:

    array_contains: '[{"status": "expired", "insuranceID": 92}]'

    is sent to the database as:

    [{\"status\": \"expired\", \"insuranceID\": 92}]

Targeting an array element by index

You can filter on the value of an element in a specific position.

{ "owned": ["Bob", "Sunny"], "fostering": ["Fido"] }
PostgreSQL
MySQL
const getUsers = await prisma.user.findMany({
where: {
comments: {
path: ['owned', '1'],
string_contains: 'Bob',
},
},
})

Filtering on object key value inside array

Depending on your provider, you can filter on the key value of an object inside an array.

Filtering on object key values within an array is only supported by the MySQL database connector. However, you can still filter on the presence of entire JSON objects.

In the following example, the value of extendedPetsData is an array of objects with a nested insurances array, which contains two objects:

[
{
"petName": "Claudine",
"petType": "House cat",
"insurances": [
{ "insuranceID": 92, "status": expired },
{ "insuranceID": 12, "status": active }
]
},
{
"petName": "Sunny",
"petType": "Gerbil"
},
{
"petName": "Gerald",
"petType": "Corn snake"
},
{
"petName": "Nanna",
"petType": "Moose"
}
]

The following query returns all users where at least one pet is a moose:

MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: '$[*].petType',
array_contains: 'Moose',
},
},
})
  • $[*] is the root array of pet objects
  • petType matches the petType key in any pet object

The following query returns all users where at least one pet has an expired insurance:

MySQL
const getUsers = await prisma.user.findMany({
where: {
extendedPetsData: {
path: '$[*].insurances[*].status',
array_contains: 'expired',
},
},
})
  • $[*] is the root array of pet objects
  • insurances[*] matches any insurances array inside any pet object
  • status matches any status key in any insurance object

Advanced example: Update a nested JSON key value

The following example assumes that the value of extendedPetsData is some variation of the following:

{
"petName": "Claudine",
"petType": "House cat",
"insurances": [
{ "insuranceID": 92, "status": "expired" },
{ "insuranceID": 12, "status": "active" }
]
}

The following example:

  1. Gets all users
  2. Change the "status" of each insurance object to "expired"
  3. Get all users that have an expired insurance where the ID is 92
PostgreSQL
MySQL
const userQueries: string | any[] = []
getUsers.forEach(user => {
if (
user.extendedPetsData &&
typeof user.extendedPetsData === 'object' &&
!Array.isArray(user.extendedPetsData)
) {
const petsObject = user.extendedPetsData as Prisma.JsonObject
const i = petsObject['insurances']
if (i && typeof i === 'object' && Array.isArray(i)) {
const insurancesArray = i as Prisma.JsonArray
insurancesArray.forEach(i => {
if (i && typeof i === 'object' && !Array.isArray(i)) {
const insuranceObject = i as Prisma.JsonObject
insuranceObject['status'] = 'expired'
}
})
const whereClause = Prisma.validator<Prisma.UserWhereInput>()({
id: user.id,
})
const dataClause = Prisma.validator<Prisma.UserUpdateInput>()({
extendedPetsData: petsObject,
})
userQueries.push(
prisma.user.update({
where: whereClause,
data: dataClause,
})
)
}
}
})
if (userQueries.length > 0) {
console.log(userQueries.length + ' queries to run!')
await prisma.$transaction(userQueries)
}
const json = [{ status: 'expired', insuranceID: 92 }]
const checkJson = await prisma.user.findMany({
where: {
extendedPetsData: {
path: ['insurances'],
array_contains: json,
},
},
})
console.log(checkJson.length)

Json FAQs

Can you select a subset of JSON key/values to return?

No - it is not yet possible to select which JSON elements to return. Prisma Client returns the entire JSON object.

Can you filter on the presence of a specific key?

No - it is not yet possible to filter on the presence of a specific key.

Is case insensitive filtering supported?

No - case insensitive filtering is not yet supported.

Edit this page on GitHub