github payloadcms/payload v1.15.3
Release 1.15.3

14 months ago

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)

  1. ➡️ Copy migration script below
  2. ➡️ Run migration script
  3. ➡️ Add new property to config
  4. 🧠 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
  }
}

Don't miss a new payload release

NewReleases is sending notifications on new releases.