如何正确删除 MongoDB 中的记录及其所有引用

war*_*der 1 mongoose mongodb node.js

我有一个user集合,并且有一个可以删除用户的 API。但是,我在其他集合中使用用户作为引用,例如也Posts有一个 userId 引用visitRequests

有没有正确的方法来做到这一点?或者我应该在每个集合中执行这样的特定查询?

await User.findOneAndDelete({ _id: id });
await visitRequestModel.findOneAndDelete(
  {_userId: id},
);
...
Run Code Online (Sandbox Code Playgroud)

另外,我想更改帖子集合中的状态而不是删除它。

而且,这可以用聚合方法来完成吗?

T-S*_*ark 6

一种流行的方法是使用 MongoDB 的前/后保存挂钩进行删除查询。但我建议的更好的解决方案是使用 MongoDB 事务,因为要删除的引用数量可能会随着应用程序的增长而增加,并且当您希望更新帖子的状态而不是删除时。如果从关系数据库固有的 ACID 角度来看,事务会非常有帮助。为了避免不一致,因为在您上面建议的方法中,甚至使用钩子时,一个查询可能会在其他查询运行后失败,这对您的应用程序来说可能非常糟糕。所以事务解决了这个问题,因此解决方法如下:

  • 您必须连接到数据库后才能获取 Mongodb 连接。 const connection = mongoose.connection;
  • 您现在可以实施交易,如下所示:
const session = await connection.startSession();
console.log('started new session')
// it is advisable to use a try/catch block here to handle failures and rollback
try {
  await session.startTransaction();
  console.log('transaction started'); //just some logging;
  await User.findOneAndDelete({ _id: id }, { session });
  await visitRequestModel.findOneAndDelete({ _id: id }, { session });
  // now to update your post's status
  await Posts.updateOne({ _id: id }, { status: 'newStatus' }, { session });
  await session.commitTransaction();
  console.log('transaction(delete operation) successful');

} catch (error) {
   console.log('transaction failed');
   throw new Error(err);
   await session.abortTransaction();
}
await connection.endSession();
console.log('session ended')
Run Code Online (Sandbox Code Playgroud)

这样,您可以保证数据的一致性,因为abortTransaction()如果流程中发生错误或查询失败,则会调用 ,并且一切都会回滚到之前的状态。您还可以添加其他与会话无关的查询,只需记住以{ session }参数传递的查询是与正在运行的事务关联的查询。

注意:如果您使用自托管 MongoDB 实例(可能是本地安装),您可能必须配置 MongoDB 副本集/分片集群,因为独立 MongoDB 安装不支持事务。但如果您使用的是 Atlas,那么您无需进行任何更多配置即可使用。

希望这可以帮助...