/** * Migration Script: Profile Fields Restructure * * This script migrates member data from the old schema to the new schema: * - Removes `skills` field * - Converts `offering` from String to { text: String, tags: [String] } * - Converts `lookingFor` from String to { text: String, tags: [String] } * - Converts `peerSupport.topics` to `peerSupport.skillTopics` and `peerSupport.supportTopics` * - Removes `privacy.skills` */ import mongoose from 'mongoose'; import Member from '../server/models/member.js'; import { connectDB } from '../server/utils/mongoose.js'; // Curated list of conversational support topics const CONVERSATIONAL_TOPICS = [ 'Co-founder relationships', 'Burnout prevention', 'Impostor syndrome', 'Work-life boundaries', 'Conflict resolution', 'General chat & support', ]; async function migrateProfileFields() { try { await connectDB(); console.log('Connected to database'); // Find all members const members = await Member.find({}); console.log(`Found ${members.length} members to migrate`); let migratedCount = 0; let skippedCount = 0; for (const member of members) { let needsUpdate = false; const updates = {}; // Migrate skills -> offering.tags (if offering doesn't have tags yet) if (member.skills && member.skills.length > 0) { console.log(`\nMember ${member.name} (${member.email}):`); console.log(` - Has skills: ${member.skills.join(', ')}`); // If offering is still a string, convert it and add skills as tags if (typeof member.offering === 'string') { updates['offering'] = { text: member.offering || '', tags: member.skills, // Move skills to offering tags }; console.log(` - Migrating skills to offering.tags`); needsUpdate = true; } // Remove skills field updates.$unset = { skills: 1 }; needsUpdate = true; } // Migrate offering from string to object (if not already done) if (typeof member.offering === 'string' && !updates['offering']) { updates['offering'] = { text: member.offering || '', tags: [], }; console.log(` - Converting offering to object structure`); needsUpdate = true; } // Migrate lookingFor from string to object if (typeof member.lookingFor === 'string') { updates['lookingFor'] = { text: member.lookingFor || '', tags: [], }; console.log(` - Converting lookingFor to object structure`); needsUpdate = true; } // Migrate peer support topics if (member.peerSupport?.topics && member.peerSupport.topics.length > 0) { const skillTopics = []; const supportTopics = []; // Split topics into skill-based and conversational for (const topic of member.peerSupport.topics) { if (CONVERSATIONAL_TOPICS.includes(topic)) { supportTopics.push(topic); } else { skillTopics.push(topic); } } updates['peerSupport.skillTopics'] = skillTopics; updates['peerSupport.supportTopics'] = supportTopics; updates['$unset'] = { ...(updates['$unset'] || {}), 'peerSupport.topics': 1 }; console.log(` - Splitting peer support topics:`); console.log(` Skill topics: ${skillTopics.join(', ') || 'none'}`); console.log(` Support topics: ${supportTopics.join(', ') || 'none'}`); needsUpdate = true; } // Remove privacy.skills if it exists if (member.privacy?.skills) { updates['$unset'] = { ...(updates['$unset'] || {}), 'privacy.skills': 1 }; needsUpdate = true; } // Apply updates if (needsUpdate) { const updateOps = { ...updates }; const unsetOps = updateOps.$unset; delete updateOps.$unset; const finalUpdate = {}; if (Object.keys(updateOps).length > 0) { finalUpdate.$set = updateOps; } if (unsetOps && Object.keys(unsetOps).length > 0) { finalUpdate.$unset = unsetOps; } await Member.updateOne({ _id: member._id }, finalUpdate); console.log(` āœ“ Updated`); migratedCount++; } else { skippedCount++; } } console.log('\n=== Migration Complete ==='); console.log(`Total members: ${members.length}`); console.log(`Migrated: ${migratedCount}`); console.log(`Skipped (already migrated): ${skippedCount}`); } catch (error) { console.error('Migration error:', error); throw error; } finally { await mongoose.connection.close(); console.log('\nDatabase connection closed'); } } // Run migration migrateProfileFields() .then(() => { console.log('\nāœ“ Migration script completed successfully'); process.exit(0); }) .catch((error) => { console.error('\nāœ— Migration script failed:', error); process.exit(1); });