Fix dedup migration: 3 bulk SQL queries instead of per-dupe loop

Was: for loop with 3 IPC calls per duplicate group = thousands of
round-trips = 10+ minutes on phone. Now: 3 bulk UPDATE/DELETE
statements that run in SQLite directly. One-time migration,
subsequent launches skip (COUNT=0).
This commit is contained in:
4aiman 2026-05-30 20:55:20 +03:00
commit d365554a7b

View file

@ -1141,21 +1141,22 @@ async function runMigrations() {
await addSuppCol("omega6_mg", "REAL"); // омега-6
await addSuppCol("omega9_mg", "REAL"); // омега-9
// Deduplicate products: keep lowest id, reassign food_log and recipe_ingredients
// Deduplicate products: keep lowest id per name_lower, reassign refs, delete dupes
// All in bulk SQL — no per-row loop
try {
const dupes = await select(
"SELECT name_lower, MIN(id) as keep_id, COUNT(*) as cnt FROM products WHERE name_lower IS NOT NULL GROUP BY name_lower HAVING cnt > 1"
);
if (dupes.length > 0) {
for (const d of dupes) {
// Reassign food_log entries to the kept product
await execute("UPDATE food_log SET product_id = ?1 WHERE product_id IN (SELECT id FROM products WHERE name_lower = ?2 AND id != ?1)", [d.keep_id, d.name_lower]);
// Reassign recipe_ingredients
await execute("UPDATE recipe_ingredients SET product_id = ?1 WHERE product_id IN (SELECT id FROM products WHERE name_lower = ?2 AND id != ?1)", [d.keep_id, d.name_lower]);
// Delete duplicates
await execute("DELETE FROM products WHERE name_lower = ?1 AND id != ?2", [d.name_lower, d.keep_id]);
}
console.log(`[db.js] Deduplicated ${dupes.length} product groups`);
const dupeCount = await select("SELECT COUNT(*) as cnt FROM products WHERE name_lower IS NOT NULL AND id NOT IN (SELECT MIN(id) FROM products WHERE name_lower IS NOT NULL GROUP BY name_lower)");
if (dupeCount[0].cnt > 0) {
// Reassign food_log to kept (MIN) id
await execute(`UPDATE food_log SET product_id = (
SELECT MIN(p2.id) FROM products p2 WHERE p2.name_lower = (SELECT p3.name_lower FROM products p3 WHERE p3.id = food_log.product_id)
) WHERE product_id IN (SELECT id FROM products WHERE name_lower IS NOT NULL AND id NOT IN (SELECT MIN(id) FROM products WHERE name_lower IS NOT NULL GROUP BY name_lower))`);
// Reassign recipe_ingredients
await execute(`UPDATE recipe_ingredients SET product_id = (
SELECT MIN(p2.id) FROM products p2 WHERE p2.name_lower = (SELECT p3.name_lower FROM products p3 WHERE p3.id = recipe_ingredients.product_id)
) WHERE product_id IN (SELECT id FROM products WHERE name_lower IS NOT NULL AND id NOT IN (SELECT MIN(id) FROM products WHERE name_lower IS NOT NULL GROUP BY name_lower))`);
// Delete dupes
await execute("DELETE FROM products WHERE name_lower IS NOT NULL AND id NOT IN (SELECT MIN(id) FROM products WHERE name_lower IS NOT NULL GROUP BY name_lower)");
console.log(`[db.js] Deduplicated ${dupeCount[0].cnt} products`);
}
} catch (e) { console.error("[db.js] dedup error:", e); }