From c0afa102bb30fcdb3202a2b7745ed039b6aec2b6 Mon Sep 17 00:00:00 2001 From: Cedric Vidal Date: Thu, 26 Feb 2026 14:55:12 -0800 Subject: [PATCH] fix: bootstrap _migrations indexes before mongo-migrate-ts runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cosmos DB (MongoDB API) rejects sort operations on unindexed fields. mongo-migrate-ts internally does .sort({ timestamp: -1 }) to list applied migrations. Without a pre-existing index on the _migrations collection, the migration job fails with BadRequest (400). This is a chicken-and-egg problem — we cannot use a migration to create the index because the framework cannot read the collection without it. The fix pre-creates { timestamp: -1 } and { className: 1 } indexes on _migrations before handing off to mongoMigrateCli. --- packages/db-migrations/src/migrate.ts | 35 ++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/db-migrations/src/migrate.ts b/packages/db-migrations/src/migrate.ts index 70d5df122..753f8bb51 100644 --- a/packages/db-migrations/src/migrate.ts +++ b/packages/db-migrations/src/migrate.ts @@ -16,6 +16,7 @@ */ import { mongoMigrateCli } from "mongo-migrate-ts"; +import { MongoClient } from "mongodb"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; @@ -32,10 +33,42 @@ const database = process.env.MONGO_DATABASE ?? "requests-db"; +const MIGRATIONS_COLLECTION = "_migrations"; + +/** + * Bootstrap required indexes on the _migrations collection BEFORE + * mongo-migrate-ts runs. + * + * Cosmos DB (MongoDB API) rejects sort operations on unindexed fields. + * mongo-migrate-ts internally does `.sort({ timestamp: -1 })` to list and + * find the last applied migration, so this index must exist before the + * framework even checks migration status. + * + * This is a chicken-and-egg issue — we can't use a migration to create + * the index because the framework can't read the migrations collection + * without it. + */ +async function ensureMigrationsCollectionIndexes(): Promise { + const client = await MongoClient.connect(uri); + try { + const db = client.db(database); + const col = db.collection(MIGRATIONS_COLLECTION); + await col.createIndex({ timestamp: -1 }).catch(() => {}); + await col.createIndex({ className: 1 }).catch(() => {}); + console.log( + `Ensured indexes on ${MIGRATIONS_COLLECTION} collection`, + ); + } finally { + await client.close(); + } +} + +await ensureMigrationsCollectionIndexes(); + mongoMigrateCli({ uri, database, migrationsDir: join(__dirname, "migrations"), - migrationsCollection: "_migrations", + migrationsCollection: MIGRATIONS_COLLECTION, globPattern: "**/*.ts", });