TL;DR
PayloadCMS v1.15.3 introduces significant performance improvements for version-enabled collections through a new query optimization system. This release adds a latest flag to document versions, dramatically speeding up queries. It also fixes critical bugs with globals, including incorrect date handling and UI issues with the unpublish button. The update requires running a migration script and adding a new configuration option.
Highlight of the Release
- Significant performance improvements for version-enabled collections through a new query optimization system
- Fixed bug where draft globals incorrectly displayed unpublish button
- Fixed issue with globals not saving updatedAt, createdAt, and version dates correctly
- Added new database configuration option
queryDrafts_2_0 to enable optimized queries
Migration Guide
for v1.15.3
To take advantage of the performance improvements in this release, follow these steps:
Step 1: Create the Migration Script
Create a file (e.g., scripts/improveVersionsQueryPerformance.ts) with the migration script provided in the release notes.
Step 2: Backup Your Database
Before running any migration, it's strongly recommended to backup your database to prevent data loss.
Step 3: Run the Migration Script
Execute the script using the appropriate command for your project structure:
# If your config is at src/payload.config.ts
PAYLOAD_CONFIG_PATH=src/payload.config.ts npx ts-node -T scripts/improveVersionsQueryPerformance.ts
The script will:
- Process collections with versioning enabled
- Add a
latest: true flag to the most recent version of each document
- Process globals with versioning enabled
- Log progress as it completes each collection
Step 4: Update Your Configuration
Add the new configuration option to your payload.config.ts file:
const config = {
// ... rest of your config
database: {
queryDrafts_2_0: true
}
}
Step 5: Verify the Migration
After completing the migration and updating your configuration:
- Restart your application
- Test operations involving versioned collections to ensure they work correctly
- Monitor performance to confirm the expected improvements
If you encounter any issues, you can temporarily disable the new query strategy by setting queryDrafts_2_0: false while troubleshooting.
Upgrade Recommendations
Priority Level: Medium-High
This upgrade is recommended for all PayloadCMS users who utilize versioning in their collections or globals, as it provides significant performance improvements and fixes important bugs with global documents.
Who should prioritize this update:
- Projects with many versioned documents that may be experiencing performance issues
- Applications using global documents with versioning enabled
- Sites where content editors are experiencing slow loading times when working with versioned content
Upgrade Process:
- Update to v1.15.3 using your package manager:
npm install [email protected]
# or
yarn add [email protected]
- Follow the migration guide to run the script and update your configuration
- Test thoroughly after upgrading, especially operations involving versioned collections and globals
The update is backward compatible and should not cause any disruption to existing functionality, provided the migration script is run correctly.
Bug Fixes
Fixed Issues with Globals
This release addresses two important bugs related to global documents:
-
Draft Globals Unpublish Button Issue
- Fixed a bug where draft globals were always displaying the unpublish button
- The unpublish button will now only appear when appropriate based on the document status
-
Global Document Timestamps
- Fixed an issue where globals were not correctly saving
updatedAt, createdAt, and version dates
- All timestamp fields will now be properly recorded and maintained for global documents
New Features
Improved Query Performance for Versioned Collections
PayloadCMS v1.15.3 introduces a significant performance enhancement for collections with versioning enabled. This feature:
- Adds a
latest flag to the most recent version of each document
- Optimizes database queries by directly targeting the latest versions
- Dramatically improves query speed for version-enabled collections
- Can be toggled on/off via the new
queryDrafts_2_0 configuration option
To implement this feature, you'll need to:
- Run the provided migration script to add the
latest flag to your existing documents
- Add the
queryDrafts_2_0: true option to your database configuration
// In your payload.config.ts
const config = {
// ... rest of your config
database: {
queryDrafts_2_0: true
}
}
This optimization is particularly beneficial for projects with large numbers of versioned documents.
Security Updates
No specific security fixes were included in this release.
Performance Improvements
Version Query Optimization
The major performance improvement in this release focuses on optimizing queries for version-enabled collections:
- New Query Strategy: Implements a more efficient approach to retrieving the latest versions of documents by adding a
latest flag to the most recent version of each document
- Reduced Query Complexity: Simplifies the process of finding the latest version of a document, resulting in faster database operations
- Scalability Improvement: Particularly beneficial for collections with many documents and versions
- Migration Process: The provided migration script efficiently processes documents in batches (100 at a time by default) to minimize database load during the update
- Configurable: The new query strategy can be enabled or disabled via the
queryDrafts_2_0 configuration option
This optimization is part of ongoing efforts to improve PayloadCMS performance as projects scale.
Impact Summary
PayloadCMS v1.15.3 delivers a focused update that significantly improves performance for version-enabled collections through a new query optimization system. By adding a latest flag to document versions and introducing the queryDrafts_2_0 configuration option, the CMS can now more efficiently retrieve the latest versions of documents, resulting in faster database operations.
The release also addresses two important bugs related to global documents: fixing incorrect display of unpublish buttons on draft globals and ensuring proper saving of timestamp fields (updatedAt, createdAt, and version dates).
While this update requires running a migration script, the performance benefits make it worthwhile for most users, especially those with large collections of versioned documents. The migration process is designed to be efficient, processing documents in batches to minimize database load.
This release represents an important step in PayloadCMS's ongoing efforts to improve performance and reliability, particularly as projects scale with more content and versions.
Full Release Notes
1.15.3 (2023-09-05)
Bug Fixes
- draft globals always displaying unpublish button (9bc072c)
- globals not saving updatedAt and createdAt and version dates correctly (9fbabc8)
Features
✨ Improving version enabled query speed (related PR)
- ➡️ Copy migration script below
- ➡️ Run migration script
- ➡️ Add new property to config
- 🧠 While this migration script is very basic, it is always a good idea to backup your DB before running migrations
1. The migration script
const payload = require('payload');
require('dotenv').config();
const { PAYLOAD_SECRET, MONGODB_URI } = process.env;
// This function adds a `latest` flag for each documents newest version
// to improve query performance on versions/drafts
const improveVersionsQueryPerformance = async () => {
// Initialize Payload
// IMPORTANT: make sure your ENV variables are filled properly here
// as the below variable names are just for reference.
await payload.init({
secret: PAYLOAD_SECRET,
mongoURL: MONGODB_URI,
local: true,
});
async function migrateCollectionDocs(slug: string, docsAtATime = 100) {
const VersionsModel = payload.versions[slug];
const remainingDocs = await VersionsModel.aggregate([
// Sort so that newest are first
{
$sort: {
updatedAt: -1,
},
},
// Group by parent ID
// take the $first of each
{
$group: {
_id: '$parent',
_versionID: { $first: '$_id' },
version: { $first: '$version' },
updatedAt: { $first: '$updatedAt' },
createdAt: { $first: '$createdAt' },
latest: { $first: '$latest' },
},
},
{
$match: {
latest: { $eq: null },
},
},
{
$limit: docsAtATime,
},
], {
allowDiskUse: true,
})
.exec();
if (!remainingDocs || remainingDocs.length === 0) {
const newVersions = await VersionsModel.find({
latest: {
$eq: true
}
})
if (newVersions?.length) {
console.log(`Migrated ${newVersions.length} documents in the "${slug}" versions collection.`)
}
return;
}
const remainingDocIds = remainingDocs.map((doc) => doc._versionID);
await VersionsModel.updateMany(
{
_id: {
$in: remainingDocIds,
},
},
{
latest: true,
},
);
await migrateCollectionDocs(slug);
}
// For each collection
await Promise.all(
payload.config.collections.map(async ({ slug, versions }) => {
if (versions) {
return migrateCollectionDocs(slug);
}
}),
);
// For each global
await Promise.all(
payload.config.globals.map(async ({ slug, versions }) => {
if (versions) {
const VersionsModel = payload.versions[slug];
await VersionsModel.findOneAndUpdate(
{},
{ latest: true },
{
sort: { updatedAt: -1 },
},
).exec();
console.log(`Migrated the "${slug}" global.`)
}
}),
);
console.log('Done!');
process.exit(0);
};
improveVersionsQueryPerformance();
2. Running the script
This step depends on where the script is run from and where you place the script. The example below is assuming you have a similar folder structure and are running it from the root folder:
root
└─ scripts
└─ improveVersionsQueryPerformance.ts
└─ src
└─ payload.config.ts
# the command to run in the root folder
PAYLOAD_CONFIG_PATH=src/payload.config.ts npx ts-node -T scripts/improveVersionsQueryPerformance.ts
3. Adjusting your payload.config.ts file
// file: payload.config.ts
const config = {
// ... rest of your config
database: {
// You can toggle this feature on/off after running the migration
// if you need to revert to querying the previous way
queryDrafts_2_0: true
}
}