diff --git a/scripts/README.md b/scripts/README.md index 40c2a27..8755fee 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -49,3 +49,26 @@ If something goes wrong mid-run, the backup JSON contains the pre-migration stat - Identify which members had `helcimSubscriptionId` before it was unset. Backup files are gitignored (`.migration-backup-*.json`). + +--- + +## migrate-contribution-amount.cjs + +One-time migration: converts `Member.contributionTier` (String enum) to +`Member.contributionAmount` (Number). Idempotent — only touches documents that +still have the legacy field. + +### Usage + +```bash +node scripts/migrate-contribution-amount.cjs # dry-run +node scripts/migrate-contribution-amount.cjs --apply # write +``` + +### What it does + +Iterates members with `contributionTier` still set, parses each value as an integer +(valid: `"0"`, `"5"`, `"15"`, `"30"`, `"50"`), and writes the converted value to +`contributionAmount`. Unsets the old field. Skips any record that cannot be parsed. + +Safe to re-run: only matches members where `contributionTier` still exists. diff --git a/scripts/migrate-contribution-amount.cjs b/scripts/migrate-contribution-amount.cjs new file mode 100644 index 0000000..406cc1a --- /dev/null +++ b/scripts/migrate-contribution-amount.cjs @@ -0,0 +1,67 @@ +/** + * One-time migration: Member.contributionTier (String: "0"|"5"|"15"|"30"|"50") → + * Member.contributionAmount (Number). Idempotent: only acts on docs that still + * have contributionTier; safe to re-run. + * + * Usage: + * node scripts/migrate-contribution-amount.cjs # dry-run (default) + * node scripts/migrate-contribution-amount.cjs --apply # writes changes + */ +require('dotenv').config() +const mongoose = require('mongoose') + +async function run() { + const apply = process.argv.includes('--apply') + if (!process.env.MONGODB_URI) { + console.error('MONGODB_URI not set in environment') + process.exit(1) + } + + await mongoose.connect(process.env.MONGODB_URI) + const db = mongoose.connection.db + const col = db.collection('members') + + // Count docs that still have the old field + const legacyCount = await col.countDocuments({ contributionTier: { $exists: true } }) + console.log(`Found ${legacyCount} members with legacy contributionTier`) + + if (legacyCount === 0) { + console.log('Nothing to migrate.') + await mongoose.disconnect() + return + } + + const cursor = col.find({ contributionTier: { $exists: true } }) + let updated = 0 + let skipped = 0 + + while (await cursor.hasNext()) { + const doc = await cursor.next() + const raw = doc.contributionTier + const amount = parseInt(raw, 10) + if (!Number.isInteger(amount) || amount < 0) { + console.warn(` SKIP ${doc._id}: cannot parse contributionTier=${JSON.stringify(raw)}`) + skipped++ + continue + } + if (apply) { + await col.updateOne( + { _id: doc._id }, + { $set: { contributionAmount: amount }, $unset: { contributionTier: '' } }, + ) + } + updated++ + } + + console.log(`${apply ? 'Updated' : 'Would update'} ${updated} documents, skipped ${skipped}`) + if (!apply) console.log('Dry-run complete. Re-run with --apply to write changes.') + await mongoose.disconnect() +} + +run().catch(async (err) => { + console.error(err) + try { + await mongoose.disconnect() + } catch {} + process.exit(1) +})