Add script to fix duplicate contacts in database

This commit is contained in:
richardtekula
2025-11-20 08:05:27 +01:00
parent a1e9936a3f
commit 4159a2aadb

View File

@@ -0,0 +1,90 @@
import { db } from '../config/database.js';
import { contacts, emails } from '../db/schema.js';
import { eq, and, sql } from 'drizzle-orm';
import { logger } from '../utils/logger.js';
/**
* Fix duplicate contacts by merging them
* - Finds contacts with the same email address
* - Keeps the newest contact
* - Updates all emails to use the newest contact ID
* - Deletes old duplicate contacts
*/
async function fixDuplicateContacts() {
try {
logger.info('🔍 Finding duplicate contacts...');
// Find duplicate contacts (same userId + email)
const duplicates = await db
.select({
userId: contacts.userId,
email: contacts.email,
count: sql`count(*)::int`,
ids: sql`array_agg(${contacts.id} ORDER BY ${contacts.createdAt} DESC)`,
})
.from(contacts)
.groupBy(contacts.userId, contacts.email)
.having(sql`count(*) > 1`);
if (duplicates.length === 0) {
logger.success('✅ No duplicate contacts found!');
return;
}
logger.info(`Found ${duplicates.length} sets of duplicate contacts`);
let totalFixed = 0;
let totalDeleted = 0;
for (const dup of duplicates) {
const contactIds = dup.ids;
const newestContactId = contactIds[0]; // First one (ordered by createdAt DESC)
const oldContactIds = contactIds.slice(1); // Rest are duplicates
logger.info(`\n📧 Fixing duplicates for ${dup.email}:`);
logger.info(` - Keeping contact: ${newestContactId}`);
logger.info(` - Merging ${oldContactIds.length} duplicate(s): ${oldContactIds.join(', ')}`);
// Update all emails from old contacts to use the newest contact ID
for (const oldContactId of oldContactIds) {
const updateResult = await db
.update(emails)
.set({ contactId: newestContactId, updatedAt: new Date() })
.where(eq(emails.contactId, oldContactId))
.returning();
if (updateResult.length > 0) {
logger.success(` ✅ Updated ${updateResult.length} emails from ${oldContactId}${newestContactId}`);
totalFixed += updateResult.length;
}
// Delete the old duplicate contact
await db
.delete(contacts)
.where(eq(contacts.id, oldContactId));
logger.success(` 🗑️ Deleted duplicate contact: ${oldContactId}`);
totalDeleted++;
}
}
logger.success(`\n✅ Cleanup complete!`);
logger.success(` - Fixed ${totalFixed} emails`);
logger.success(` - Deleted ${totalDeleted} duplicate contacts`);
} catch (error) {
logger.error('❌ Error fixing duplicate contacts:', error);
throw error;
}
}
// Run the script
fixDuplicateContacts()
.then(() => {
logger.success('🎉 Script completed successfully!');
process.exit(0);
})
.catch((error) => {
logger.error('💥 Script failed:', error);
process.exit(1);
});