Relationships in Payload CMS refer to the connections established between different documents within the CMS. These relationships allow users to link various content types, thereby creating a more interconnected and dynamic content structure. Payload CMS supports multiple types of relationships, including:
One-to-One: A single document is linked to another single document.
One-to-Many: A single document is linked to multiple documents.
Many-to-Many: Multiple documents are linked to multiple other documents.
Polymorphic Relationships: Relationships that can refer to documents from different collections.
By leveraging these relationship types, Payload CMS enables users to build complex content architectures that cater to a wide range of applications, from e-commerce sites to blogs with related posts.
Use Cases for Relationships
Relationships in Payload CMS are highly versatile and can be utilized in various scenarios to enhance data management and user experience. Some practical use cases include:
E-commerce: Linking products to categories, manufacturers, and related products.
Blogging: Connecting related blog posts to increase reader engagement and time on site.
Digital Asset Management: Associating media files with specific projects or clients.
Enterprise Applications: Managing hierarchical structures such as departments and employees.
By using relationships, developers can ensure data integrity, reduce redundancy, and create cohesive content structures that are easy to manage and query.
Setting Up Relationships in Payload CMS
Payload CMS offers a comprehensive and flexible system for setting up relationships between documents. The following sections provide detailed instructions on how to configure and use relationship fields in Payload CMS.
Basic Configuration
To define a relationship field in Payload CMS, you need to specify several key configuration properties in your collection's configuration. Here are the important properties:
Config Option | Description |
---|---|
name | Property name when stored and retrieved from the database. |
relationTo | Specifies one or many collections to assign relationships to. |
hasMany | Boolean indicating if the field can have multiple relations. |
minRows | Minimum allowed items during validation when a value is present. Used in conjunction with |
maxRows | Maximum allowed items during validation when a value is present. Used in conjunction with |
maxDepth | Limits depth of related documents when queried. |
label | Text for the field label in the Admin panel or an object with keys for each language. |
unique | Enforces unique values for each entry in the collection. |
validate | Custom validation function executed on both the Admin panel and backend. |
index | Create an index for faster queries. |
saveToJWT | Include field data in the user JWT if nested in a config supporting Authentication. |
hooks | Field-based hooks for custom logic. |
access | Field-based access control to manage visibility and permissions. |
hidden | Restrict field visibility from all APIs. |
defaultValue | Data used as the field's default value. |
localized | Enable localization for the field. Requires localization to be enabled in the Base config. |
required | Make the field mandatory. |
admin | Admin-specific configuration. |
Admin Config
The Relationship field type includes additional properties for configuring the Admin UI:
Property | Description |
---|---|
isSortable | Set to |
allowCreate | Set to |
sortOptions | Define a default sorting order for the options within a Relationship field's dropdown. |
sortOptions: 'fieldName' // Global default sort field in ascending order
sortOptions: {
"pages": "fieldName1",
"posts": "-fieldName2",
"categories": "fieldName3"
}
Filtering Relationship Options
Options for relationships can be dynamically limited through the filterOptions
property, which can be a query or a function returning a query:
import { CollectionConfig } from 'payload/types';
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
fields: [
{
name: 'purchase',
type: 'relationship',
relationTo: ['products', 'services'],
filterOptions: ({ relationTo, siblingData }) => {
if (relationTo === 'products') {
return { stock: { greater_than: siblingData.quantity } };
}
if (relationTo === 'services') {
return { isAvailable: { equals: true } };
}
return {}; // Default filter
},
},
],
};
How Data is Saved
Depending on the configuration, the shape of the data can vary. Below are examples for different relationship types.
Has One{
slug: 'example-collection',
fields: [
{
name: 'owner',
type: 'relationship',
relationTo: 'users',
hasMany: false,
}
]
}
Data Shape:
{
"owner": "6031ac9e1289176380734024"
}
Has One - Polymorphic{
slug: 'example-collection',
fields: [
{
name: 'owner',
type: 'relationship',
relationTo: ['users', 'organizations'],
hasMany: false,
}
]
}
Data Shape:
{
"owner": {
"relationTo": "organizations",
"value": "6031ac9e1289176380734024"
}
}
Has Many{
slug: 'example-collection',
fields: [
{
name: 'owners',
type: 'relationship',
relationTo: 'users',
hasMany: true,
}
]
}
Data Shape:
{
"owners": ["6031ac9e1289176380734024", "602c3c327b811235943ee12b"]
}
Has Many - Polymorphic{
slug: 'example-collection',
fields: [
{
name: 'owners',
type: 'relationship',
relationTo: ['users', 'organizations'],
hasMany: true,
required: true,
}
]
}
Data Shape:
{
"owners": [
{ "relationTo": "users", "value": "6031ac9e1289176380734024" },
{ "relationTo": "organizations", "value": "602c3c327b811235943ee12b" }
]
}
Querying and Filtering Polymorphic Relationships
Querying polymorphic relationships can vary based on how the data is stored. For example:
Query by Document ID:
?where[field.value][equals]=6031ac9e1289176380734024
Query by Collection Slug:
?where[field.relationTo][equals]=your-collection-slug
Practical Examples and Tutorials
Real-world Use Case Scenarios
Let's explore a few practical examples to understand the application of relationships in Payload CMS.
Example Tutorial from "Learn with Jason"In a detailed session on Learn with Jason, James Mikrut, the CEO of Payload CMS, demonstrated how to set up a scalable design system for enterprise websites using Payload CMS and Next.js. This tutorial provides valuable insights into the process of setting up and managing relationships within Payload CMS.
Setting Up the RepositoryRepositories:
Steps Overview:
Install Dependencies:
yarn install --legacy-peer-deps
Set up environment variables using
.env.example
for MongoDB connection and Payload secret.Server Configuration: Utilize
server.ts
to initialize an Express server and seed initial data.
Config File:
File:
payload.config.ts
Collections and Globals:
Example includes
media
,page
, andusers
collections.Globals for singleton structures like main menu and footer.
Pages Collection Example:
File:
collections/pages.ts
Toggle features such as drafts and versions.
Access control settings for read permissions based on user login status.
Defining fields, including dynamic conditions to render fields based on specific criteria.
Next.js Structure:
Utilizes
getStaticProps
to fetch data using Apollo Client.Example of caching global data to optimize build performance.
Components:
Hero Component: Choosing and rendering hero types based on selection.
Blocks Component: Dynamically rendering content blocks.
Hero Component Example:
import { HeroHighImpact } from './HeroHighImpact';
import { HeroMediumImpact } from './HeroMediumImpact';
import { HeroLowImpact } from './HeroLowImpact';
const components = {
highImpact: HeroHighImpact,
mediumImpact: HeroMediumImpact,
lowImpact: HeroLowImpact
};
export const Hero = ({ type, ...props }) => {
const HeroComponent = components[type];
return HeroComponent ? <HeroComponent {...props} /> : null;
};
Integrating Relationships with Other Systems
Payload CMS also supports seamless integrations with other systems, such as Supabase, for enhanced functionality.
Example of Payload CMS and Supabase IntegrationSetting Up Payload CMS with Supabase:
Create a Supabase Project and Database: Configure environment variables for the retrieval plugin.
export OPENAI_API_KEY=<open_ai_api_key> export DATASTORE=supabase export SUPABASE_URL=<supabase_url> export SUPABASE_SERVICE_ROLE_KEY=<supabase_key>
Replace with Postgres-specific variables if needed.
export DATASTORE=postgres export PG_HOST=<postgres_host_url> export PG_PASSWORD=<postgres_password>
Local Instance for Development:
supabase start
Apply necessary migrations: Examples in
examples/providers/supabase/migrations/
.
Authentication and Permissions: Supabase provides robust authentication and permission layers.
Authentication Flow:
// Sign in with email and password
await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'securepassword',
});
// Sign out
await supabase.auth.signOut();
Permissions and Row Level Security (RLS):
-- Enable RLS for a table
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
-- Create a policy that allows users to access their own records
CREATE POLICY user_records ON your_table FOR SELECT USING (auth.uid() = user_id);
Data Modeling and Relations:
Design database schema visually using Entity Relationship Diagrams (ERDs).
Utilize foreign keys for one-to-one, one-to-many, and many-to-many relationships.
Improve performance by creating indexes on frequently queried columns.
Developer Insights
Developers appreciate Payload CMS for its modern UI, extensive customization options, and flexibility in handling relationships. However, there are challenges as well, such as complex initial setup and database migrations. Here are some practical tips and insights:
Use TypeScript: Strongly type Payload configurations and Next.js components to prevent errors.
Modular Structure: Break down configurations and components into manageable and reusable files.
Focus on Accessibility: Ensure all UI components and CMS inputs are accessible.
Phased Refactoring: Avoid premature refactoring; focus on functionality first, then optimize.
Alternatives and Transitions
For those looking for an alternative solution to managing related blog posts, Wisp offers an AI-powered feature that automatically suggests related blog posts, enhancing user engagement and decreasing bounce rates.
Overview of Wisp's Related Blog Posts FeatureAI-Powered Content Suggestions: Wisp uses advanced AI to automatically suggest related blog posts, saving time and effort.
Boost Engagement: Keeps readers immersed in the content ecosystem, increasing time spent on the website and guiding them towards conversions.
Showcase Expertise: Demonstrates the depth of knowledge through related posts, showcasing the expertise of content creators.
Enhance User Experience: Provides a seamless journey for readers through intelligent article suggestions.
Save Time: Allows content creators to focus on producing high-quality content as the AI handles the linking of related posts.
Conclusion
Understanding and utilizing relationships in Payload CMS can significantly enhance your content management capabilities. With extensive configuration options and support for complex relationships, Payload CMS is a powerful tool for developers building sophisticated applications. For those looking to simplify the creation of related blog posts, Wisp offers an excellent alternative, leveraging AI to provide intelligent content suggestions and enhancing user engagement.
If you're looking to explore a modern and flexible CMS, give Payload CMS a try. For those specifically interested in creating related blog posts, check out Wisp for a seamless and intelligent solution.