ghostguild-org/scripts/migrate-event-slugs.js

90 lines
2.6 KiB
JavaScript

import mongoose from "mongoose";
import dotenv from "dotenv";
import { connectDB } from "../server/utils/mongoose.js";
import Event from "../server/models/event.js";
dotenv.config();
function generateSlug(title, startDate) {
const titleSlug = title
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
if (startDate) {
const d = new Date(startDate);
const year = d.getUTCFullYear();
const month = String(d.getUTCMonth() + 1).padStart(2, "0");
const day = String(d.getUTCDate()).padStart(2, "0");
return `${year}-${month}-${day}-${titleSlug}`;
}
return titleSlug;
}
async function migrateEventSlugs() {
try {
await connectDB();
console.log("Connected to database\n");
const events = await Event.find({}).sort({ startDate: 1 }).lean();
console.log(`Found ${events.length} event(s) to process\n`);
if (events.length === 0) {
console.log("No events found.");
return;
}
// Build new slugs first so uniqueness checks don't conflict with slugs
// we're about to replace in the same run.
const updates = [];
const usedSlugs = new Set();
for (const event of events) {
let baseSlug = generateSlug(event.title, event.startDate);
let slug = baseSlug;
let counter = 1;
// Ensure slug is unique within this batch and across the DB
// (excluding the current event's own existing slug)
while (
usedSlugs.has(slug) ||
(await Event.findOne({ slug, _id: { $ne: event._id } }).lean())
) {
slug = `${baseSlug}-${counter}`;
counter++;
}
usedSlugs.add(slug);
updates.push({ event, oldSlug: event.slug, newSlug: slug });
}
// Apply updates
let changed = 0;
let skipped = 0;
for (const { event, oldSlug, newSlug } of updates) {
if (oldSlug === newSlug) {
console.log(`${event.title}`);
console.log(` slug unchanged: ${newSlug}`);
skipped++;
} else {
// Use updateOne to bypass the pre-save hook (avoids re-triggering slug generation)
await Event.updateOne({ _id: event._id }, { $set: { slug: newSlug } });
console.log(`${event.title}`);
console.log(` ${oldSlug || "(none)"}${newSlug}`);
changed++;
}
}
console.log(`\nDone. ${changed} updated, ${skipped} already correct.`);
} catch (error) {
console.error("\nMigration failed:", error);
process.exit(1);
} finally {
await mongoose.connection.close();
console.log("Database connection closed.");
}
}
migrateEventSlugs();