现象

相册照片从 130 张变成了 23 张。

起因:之前把 Netlify 每月 300 次的免费部署额度烧光了,网站停更了一段时间。这期间我在本地继续测试,上传了很多图片做验证。额度恢复、重新部署上线后,再拉代码本地预览时发现相册只剩 23 张,另外 107 张”消失”了。第一反应是数据丢了。

排查:三次误判

  1. 先查 git:照片文件和元数据都在 .gitignore 里,根本不是提交问题。
  2. 以为本地环境没连上数据库:以为数据落到了本地磁盘 + JSON。其实本地 .env 里 MongoDB 是配好的,一直连着线上库。
  3. 以为连错了库:数据一直好好躺在 MongoDB lublog 库的 gallery_images 集合里,130 条元数据一条没少——丢的不是元数据,是 107 张图片文件本身(本地测试时只存在本地磁盘,没传上去)。

根因:同步代码用”本地快照”覆盖了”线上数据”

相册有一个”同步”功能,把本地相册数据推送到线上数据库。这段同步代码的逻辑是:

1. 读取本地相册数据(把它当作最新、最全的)
2. 找出数据库里有、但本地数据里没有的记录 → 全部删除($nin)
3. 把本地数据整份写回数据库

这套逻辑成立的前提是本地数据是完整的。但当时我在本地测试,很多图片只存在本地、没传数据库,本地读到的是残缺的快照。同步一跑,数据库里那 107 条”本地没有的”真实记录,全被当成多余数据删掉了。

一句话:用残缺的本地快照,覆盖了完整的线上数据。

修复:从”全量对齐”改成”精确变更”

原代码是”先删后写”的全量对齐:

  • $nin:把数据库里”本地没有的”记录全删掉
  • 再整份写回

改成了只做精确变更:

  • 要删除的记录:必须显式列出 id,用 $in 精确删——只有明确要删的才删
  • 其余记录:只做插入或字段更新,不做无差别的全量覆盖

这样即使本地数据残缺,同步也只把”本地新增的”写上去,永远不会因为”本地没有某条”就把线上数据删掉。

教训

  1. 全量删除类操作默认危险:$nin、truncate、drop、“清空表再导入”这类代码,都要求”当前数据一定完整”才安全。看到就要警觉,先确认调用方的数据是不是可信的完整快照。
  2. “同步”类代码要防快照不完整:写同步逻辑时,默认假设”本地数据可能是残缺的”。数据边界——谁在写、从哪读、快照是否完整——必须自己 review,AI 不会替你想到”快照可能是残缺的”。
  3. 先确认数据在哪,再动手:库、集合、对象存储、本地文件,先搞清楚数据到底在哪,别按”我以为”推断,免得白折腾。
  4. 写库前先备份:任何覆盖写、批量删除前,先备份或保证可回滚,别让自己没有后悔药。