### What? This PR fixes many links in the docs as well as a few formatting and grammar issues. ### Why? To properly link users to the correct destination in the docs and present well-formatted docs. ### How? Changes to a few files in `docs/`
260 lines
13 KiB
Plaintext
260 lines
13 KiB
Plaintext
---
|
|
title: Join Field
|
|
label: Join
|
|
order: 140
|
|
desc: The Join field provides the ability to work on related documents. Learn how to use Join field, see examples and options.
|
|
keywords: join, relationship, junction, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
|
---
|
|
|
|
The Join Field is used to make Relationship and Upload fields available in the opposite direction. With a Join you can
|
|
edit and view collections
|
|
having reference to a specific collection document. The field itself acts as a virtual field, in that no new data is
|
|
stored on the collection with a Join
|
|
field. Instead, the Admin UI surfaces the related documents for a better editing experience and is surfaced by Payload's
|
|
APIs.
|
|
|
|
The Join field is useful in scenarios including:
|
|
|
|
- To surface `Orders` for a given `Product`
|
|
- To view and edit `Posts` belonging to a `Category`
|
|
- To work with any bi-directional relationship data
|
|
- Displaying where a document or upload is used in other documents
|
|
|
|
<LightDarkImage
|
|
srcLight="https://payloadcms.com/images/docs/fields/join.png"
|
|
srcDark="https://payloadcms.com/images/docs/fields/join-dark.png"
|
|
alt="Shows Join field in the Payload Admin Panel"
|
|
caption="Admin Panel screenshot of Join field"
|
|
/>
|
|
|
|
For the Join field to work, you must have an existing [relationship](./relationship) or [upload](./upload) field in the
|
|
collection you are joining. This will reference the collection and path of the field of the related documents.
|
|
To add a Relationship Field, set the `type` to `join` in your [Field Config](./overview):
|
|
|
|
```ts
|
|
import type { Field } from 'payload'
|
|
|
|
export const MyJoinField: Field = {
|
|
// highlight-start
|
|
name: 'relatedPosts',
|
|
type: 'join',
|
|
collection: 'posts',
|
|
on: 'category',
|
|
// highlight-end
|
|
}
|
|
|
|
// relationship field in another collection:
|
|
export const MyRelationshipField: Field = {
|
|
name: 'category',
|
|
type: 'relationship',
|
|
relationTo: 'categories',
|
|
}
|
|
```
|
|
|
|
In this example, the field is defined to show the related `posts` when added to a `category` collection. The `on`
|
|
property is used to specify the relationship field name of the field that relates to the collection document.
|
|
|
|
With this example, if you navigate to a Category in the Admin UI or an API response, you'll now see that the Posts which
|
|
are related to the Category are populated for you. This is extremely powerful and can be used to define a wide variety
|
|
of relationship types in an easy manner.
|
|
|
|
<Banner type="success">
|
|
The Join field is extremely performant and does not add additional query overhead to your API responses until you add depth of 1 or above. It works in all database adapters. In MongoDB, we use **aggregations** to automatically join in related documents, and in relational databases, we use joins.
|
|
</Banner>
|
|
|
|
### Schema advice
|
|
|
|
When modeling your database, you might come across many places where you'd like to feature bi-directional relationships.
|
|
But here's an important consideration—you generally only want to store information about a given relationship in _one_
|
|
place.
|
|
|
|
Let's take the Posts and Categories example. It makes sense to define which category a post belongs to while editing the
|
|
post.
|
|
|
|
It would generally not be necessary to have a list of post IDs stored directly on the category as well, for a few
|
|
reasons:
|
|
|
|
- You want to have a "single source of truth" for relationships, and not worry about keeping two sources in sync with
|
|
one another
|
|
- If you have hundreds, thousands, or even millions of posts, you would not want to store all of those post IDs on a
|
|
given category
|
|
- Etc.
|
|
|
|
This is where the `join` field is especially powerful. With it, you only need to store the `category_id` on the `post`,
|
|
and Payload will automatically join in related posts for you when you query for categories. The related category is only
|
|
stored on the post itself - and is not duplicated on both sides. However, the `join` field is what enables
|
|
bi-directional APIs and UI for you.
|
|
|
|
### Using the Join field to have full control of your database schema
|
|
|
|
For typical polymorphic / many relationships, if you're using Postgres or SQLite, Payload will automatically create
|
|
a `posts_rels` table, which acts as a junction table to store all of a given document's relationships.
|
|
|
|
However, this might not be appropriate for your use case if you'd like to have more control over your database
|
|
architecture. You might not want to have that `_rels` table, and would prefer to maintain / control your own junction
|
|
table design.
|
|
|
|
<Banner type="success">
|
|
With the Join field, you can control your own junction table design, and avoid Payload's automatic _rels table creation.
|
|
</Banner>
|
|
|
|
The `join` field can be used in conjunction with _any_ collection - and if you wanted to define your own "junction"
|
|
collection, which, say, is called `categories_posts` and has a `post_id` and a `category_id` column, you can achieve
|
|
complete control over the shape of that junction table.
|
|
|
|
You could go a step further and leverage the `admin.hidden` property of the `categories_posts` collection to hide the
|
|
collection from appearing in the Admin UI navigation.
|
|
|
|
#### Specifying additional fields on relationships
|
|
|
|
Another very powerful use case of the `join` field is to be able to define "context" fields on your relationships. Let's
|
|
say that you have Posts and Categories, and use join fields on both your Posts and Categories collection to join in
|
|
related docs from a new pseudo-junction collection called `categories_posts`. Now, the relations are stored in this
|
|
third junction collection, and can be surfaced on both Posts and Categories. But, importantly, you could add
|
|
additional "context" fields to this shared junction collection.
|
|
|
|
For example, on this `categories_posts` collection, in addition to having the `category` and `post` fields, we could add
|
|
custom "context" fields like `featured` or `spotlight`,
|
|
which would allow you to store additional information directly on relationships.
|
|
The `join` field gives you complete control over any type of relational architecture in Payload, all wrapped up in a
|
|
powerful Admin UI.
|
|
|
|
## Config Options
|
|
|
|
| Option | Description |
|
|
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
| **`name`** * | To be used as the property name when retrieved from the database. [More](./overview#field-names) |
|
|
| **`collection`** * | The `slug`s having the relationship field. |
|
|
| **`on`** * | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
|
|
| **`where`** | A `Where` query to hide related documents from appearing. Will be merged with any `where` specified in the request. |
|
|
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](../queries/depth#max-depth). |
|
|
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
|
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
|
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
|
| **`defaultLimit`** | The number of documents to return. Set to 0 to return all related documents. |
|
|
| **`defaultSort`** | The field name used to specify the order the joined documents are returned. |
|
|
| **`admin`** | Admin-specific configuration. [More details](#admin-config-options). |
|
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
|
|
| **`typescriptSchema`** | Override field type generation with providing a JSON schema. |
|
|
| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) |
|
|
|
|
_* An asterisk denotes that a property is required._
|
|
|
|
|
|
## Admin Config Options
|
|
|
|
You can control the user experience of the join field using the `admin` config properties. The following options are supported:
|
|
|
|
| Option | Description |
|
|
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
|
| **`defaultColumns`** | Array of field names that correspond to which columns to show in the relationship table. Default is the collection config. |
|
|
| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. |
|
|
| **`components.Label`** | Override the default Label of the Field Component. [More details](./overview#label) |
|
|
|
|
## Join Field Data
|
|
|
|
When a document is returned that for a Join field is populated with related documents. The structure returned is an
|
|
object with:
|
|
|
|
- `docs` an array of related documents or only IDs if the depth is reached
|
|
- `hasNextPage` a boolean indicating if there are additional documents
|
|
|
|
```json
|
|
{
|
|
"id": "66e3431a3f23e684075aae9c",
|
|
"relatedPosts": {
|
|
"docs": [
|
|
{
|
|
"id": "66e3431a3f23e684075aaeb9",
|
|
// other fields...
|
|
"category": "66e3431a3f23e684075aae9c"
|
|
}
|
|
// { ... }
|
|
],
|
|
"hasNextPage": false
|
|
}
|
|
// other fields...
|
|
}
|
|
```
|
|
|
|
## Query Options
|
|
|
|
The Join Field supports custom queries to filter, sort, and limit the related documents that will be returned. In
|
|
addition to the specific query options for each Join Field, you can pass `joins: false` to disable all Join Field from
|
|
returning. This is useful for performance reasons when you don't need the related documents.
|
|
|
|
The following query options are supported:
|
|
|
|
| Property | Description |
|
|
|-------------|-----------------------------------------------------------------------------------------------------|
|
|
| **`limit`** | The maximum related documents to be returned, default is 10. |
|
|
| **`where`** | An optional `Where` query to filter joined documents. Will be merged with the field `where` object. |
|
|
| **`sort`** | A string used to order related results |
|
|
|
|
These can be applied to the local API, GraphQL, and REST API.
|
|
|
|
### Local API
|
|
|
|
By adding `joins` to the local API you can customize the request for each join field by the `name` of the field.
|
|
|
|
```js
|
|
const result = await db.findOne('categories', {
|
|
where: {
|
|
title: {
|
|
equals: 'My Category'
|
|
}
|
|
},
|
|
joins: {
|
|
relatedPosts: {
|
|
limit: 5,
|
|
where: {
|
|
title: {
|
|
equals: 'My Post'
|
|
}
|
|
},
|
|
sort: 'title'
|
|
}
|
|
}
|
|
})
|
|
```
|
|
|
|
### Rest API
|
|
|
|
The rest API supports the same query options as the local API. You can use the `joins` query parameter to customize the
|
|
request for each join field by the `name` of the field. For example, an API call to get a document with the related
|
|
posts limited to 5 and sorted by title:
|
|
|
|
`/api/categories/${id}?joins[relatedPosts][limit]=5&joins[relatedPosts][sort]=title`
|
|
|
|
You can specify as many `joins` parameters as needed for the same or different join fields for a single request.
|
|
|
|
### GraphQL
|
|
|
|
The GraphQL API supports the same query options as the local and REST APIs. You can specify the query options for each
|
|
join field in your query.
|
|
|
|
Example:
|
|
|
|
```graphql
|
|
query {
|
|
Categories {
|
|
docs {
|
|
relatedPosts(
|
|
sort: "createdAt"
|
|
limit: 5
|
|
where: {
|
|
author: {
|
|
equals: "66e3431a3f23e684075aaeb9"
|
|
}
|
|
}
|
|
) {
|
|
docs {
|
|
title
|
|
}
|
|
hasNextPage
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|