Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,29 @@ model User {
}
```

By default, the name of this field in Prisma Client queries will be `firstName_lastName`.

You can also provide your own name for the composite ID using the [`@@id`](/reference/api-reference/prisma-schema-reference#id-1) <span class="api"></span> attribute's `name` field:

```prisma highlight=7;normal
model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@id(name: "fullName", fields: [firstName, lastName])
}
```

The `firstName_lastName` field will now be named `fullName` instead.

<Admonition type="info">

Refer to the documentation on [working with composite IDs](/concepts/components/prisma-client/working-with-fields/working-with-composite-ids-and-constraints) to learn how to interact with a composite ID in Prisma Client.

</Admonition>

##### <inlinecode>@unique</inlinecode> fields as unique identifiers

In the following example, users are uniquely identified by a `@unique` field. Because the `email` field functions as a unique identifier for the model (which is required by Prisma), it must be mandatory:
Expand Down Expand Up @@ -826,6 +849,32 @@ You can optionally define a [custom unique constraint name](/concepts/components

</Admonition>

By default, the name of this field in Prisma Client queries will be `authorId_title`.

You can also provide your own name for the composite unique constraint using the [`@@unique`](/concepts/components/prisma-schema/names-in-underlying-database#constraint-and-index-names) <span class="api"></span> attribute's `name` field:

```prisma highlight=10;normal
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categories Category[] @relation(references: [id])

@@unique(name: "authorTitle", [authorId, title])
}
```

The `authorId_title` field will now be named `authorTitle` instead.

<Admonition type="info">

Refer to the documentation on [working with composite unique identifiers](/concepts/components/prisma-client/working-with-fields/working-with-composite-ids-and-constraints) to learn how to interact with a composite unique constraints in Prisma Client.

</Admonition>

#### Composite type unique constraints

When using the MongoDB provider in version `3.12.0` and later, you can define a unique constraint on a field of a [composite type](#defining-composite-types) using the syntax `@@unique([compositeType.field])`. As with other fields, composite type fields can be used as part of a multi-column unique constraint.
Expand Down
93 changes: 0 additions & 93 deletions content/200-concepts/100-components/02-prisma-client/030-crud.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -325,99 +325,6 @@ const user = await prisma.user.findUnique({
})
```

### Get record by compound ID or compound unique identifier

<Admonition type="warning">

**MongoDB does not support `@@id`**<br />
MongoDB does not support composite IDs, which means you cannot identify a model with a `@@id` attribute.

</Admonition>

The following examples demonstrate how to retrieve records by a compound ID or unique identifier, defined by [`@@id`](/reference/api-reference/prisma-schema-reference#id-1) <span class="api"></span> or [`@@unique`](/reference/api-reference/prisma-schema-reference#unique-1) <span class="api"></span>.

The following Prisma model defines a compound ID:

<TabbedContent tabs={[<FileWithIcon text="Relational databases only" icon="database"/>]}>
<tab>

```prisma highlight=6;normal
model TimePeriod {
year Int
quarter Int
total Decimal

@@id([year, quarter])
}
```

</tab>
<tab>
</tab>
</TabbedContent>

To retrieve a time period by this compound ID, use the generated `year_quarter` field, which follows the `fieldName1_fieldName2` pattern:

<TabbedContent tabs={[<FileWithIcon text="Relational databases only" icon="database"/>]}>
<tab>

```ts
const timePeriod = await prisma.timePeriod.findUnique({
where: {
year_quarter: {
quarter: 4,
year: 2020,
},
},
})
```

</tab>
<tab>
</tab>
</TabbedContent>

The following Prisma model defines a compound unique identifier with a custom name (`timePeriodId`)

<TabbedContent tabs={[<FileWithIcon text="Relational databases only" icon="database"/>]}>
<tab>

```prisma highlight=6;normal
model TimePeriod {
year Int
quarter Int
total Decimal

@@unique(fields: [year, quarter], name: "timePeriodId")
}
```

</tab>
<tab>
</tab>
</TabbedContent>

To retrieve a time period by this unique identifier, use the custom `timePeriodId` field:

<TabbedContent tabs={[<FileWithIcon text="Relational databases only" icon="database"/>]}>
<tab>

```ts
const timePeriod = await prisma.timePeriod.findUnique({
where: {
timePeriodId: {
quarter: 4,
year: 2020,
},
},
})
```

</tab>
<tab>
</tab>
</TabbedContent>

### Get all records

The following [`findMany`](/reference/api-reference/prisma-client-reference#findmany) <span class="api"></span> query returns _all_ `User` records:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
---
title: 'Working with compound IDs and unique constraints'
metaTitle: 'Working with compound IDs and unique constraints (Concepts)'
metaDescription: 'How to read, write, and filter by compound IDs and unique constraints.'
tocDepth: 2
---

<TopBlock>

Composite IDs and compound unique constraints can be defined in your Prisma schema using the [`@@id`](/reference/api-reference/prisma-schema-reference#id-1) <span class="api"></span> and [`@@unique`](/reference/api-reference/prisma-schema-reference#unique-1) <span class="api"></span> attributes.

<Admonition type="warning">

**MongoDB does not support `@@id`**<br />
MongoDB does not support composite IDs, which means you cannot identify a model with a `@@id` attribute.

</Admonition>

A composite ID or compound unique constraint uses the combined values of two fields as a primary key or identifier in your database table. In the following example, the `postId` field and `userId` field are used as a composite ID for a `Like` table:

```prisma highlight=22;normal
model User {
id Int @id @default(autoincrement())
name String
post Post[]
likes Like[]
}

model Post {
id Int @id @default(autoincrement())
content String
User User? @relation(fields: [userId], references: [id])
userId Int?
likes Like[]
}

model Like {
postId Int
userId Int
User User @relation(fields: [userId], references: [id])
Post Post @relation(fields: [postId], references: [id])

@@id([postId, userId])
}
```

Querying for records from the `Like` table (e.g. using `prisma.like.findMany()`) would return objects that look as follows:

```json
{
"postId": 1,
"userId": 1
}
```

Although there are only two fields in the response, those two fields make up a compound ID named `postId_userId`.

You can also create a named compound ID or compound unique constraint by using the `@@id` or `@@unique` attributes' `name` field. For example:

```prisma highlight=7;normal
model Like {
postId Int
userId Int
User User @relation(fields: [userId], references: [id])
Post Post @relation(fields: [postId], references: [id])

@@id(name: "likeId", [postId, userId])
}
```

</TopBlock>

## Where you can use compound IDs and unique constraints

Compound IDs and compound unique constraints can be used when working with _unique_ data.

Below is a list of Prisma Client functions that accept a compound ID or compound unique constraint in the `where` filter of the query:

- `findUnique`
- `findUniqueOrThrow`
- `delete`
- `update`
- `upsert`

A composite ID and a composite unique constraint is also usable when creating relational data with `connect` and `connectOrCreate`.

## Filtering records by a compound ID or unique constraint

Although your query results will not display a compound ID or unique constraint as a field, you can use these compound values to filter your queries for unique records:

```ts highlight=3-6;normal
const like = await prisma.like.findUnique({
where: {
likeId: {
Comment thread
nikolasburk marked this conversation as resolved.
userId: 1,
postId: 1,
},
},
})
```

<Admonition type="info">

Note composite ID and compound unique constraint keys are only available as filter options for _unique_ queries such as `findUnique` and `findUniqueOrThrow`. See the [section](/concepts/components/prisma-client/working-with-fields/working-with-composite-ids/#where-you-can-use-compound-ids-and-unique-identifiers) above for a list of places these fields may be used.

</Admonition>

## Deleting records by a compound ID or unique constraint

A compound ID or compound unique constraint may be used in the `where` filter of a `delete` query:

```ts highlight=3-6;normal
const like = await prisma.like.delete({
where: {
likeId: {
userId: 1,
postId: 1,
},
},
})
```

## Updating and upserting records by a compound ID or unique constraint

A compound ID or compound unique constraint may be used in the `where` filter of an `update` query:

```ts highlight=3-6;normal
const like = await prisma.like.update({
where: {
likeId: {
userId: 1,
postId: 1,
},
},
data: {
postId: 2,
},
})
```

They may also be used in the `where` filter of an `upsert` query:

```ts highlight=3-6;normal
await prisma.like.upsert({
where: {
likeId: {
userId: 1,
postId: 1,
},
},
update: {
userId: 2,
},
create: {
userId: 2,
postId: 1,
},
})
```

## Filtering relation queries by a compound ID or unique constraint

Compound IDs and compound unique constraint can also be used in the `connect` and `connectOrCreate` keys used when connecting records to create a relationship.

For example, consider this query:

```ts highlight=6-9;normal
await prisma.user.create({
data: {
name: 'Alice',
likes: {
connect: {
likeId: {
postId: 1,
userId: 2,
},
},
},
},
})
```

The `likeId` compound ID is used as the identifier in the `connect` object that is used to locate the `Like` table's record that will be linked to the new user: `"Alice"`.

Similarly, the `likeId` can be used in `connectOrCreate`'s `where` filter to attempt to locate an existing record in the `Like` table:

```ts highlight=10-13;normal
await prisma.user.create({
data: {
name: 'Alice',
likes: {
connectOrCreate: {
create: {
postId: 1,
},
where: {
likeId: {
postId: 1,
userId: 1,
},
},
},
},
},
})
```
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,7 @@ See: [Working with `Json` fields](working-with-json-fields)
## Working with scalar lists / scalar arrays

See: [Working with scalar lists / arrays](working-with-scalar-lists-arrays)

## Working with composite IDs and compound unique constraints

See: [Working with composite IDs and compound unique constraints](working-with-composite-ids-and-constraints)