You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sequelize实现单用户软删除会话不影响另一用户的方案问询

解决方案:实现单用户独立删除会话(不影响对方)

你的问题核心在于全局软删除(paranoid模式)会让所有用户都看不到被删除的会话,而你需要的是用户级别的软删除——每个用户可以单独标记会话为自己已删除,不影响另一方的可见性。下面是具体的实现步骤:

1. 修改会话模型:添加用户专属的软删除字段

首先,我们需要去掉全局的paranoid: true,转而给每个会话参与者添加独立的删除时间字段,这样就能分别控制两个用户的会话可见性:

const Conversation = db.define("Conversation", {
  // 新增两个用户专属的软删除字段
  user1DeletedAt: {
    type: db.DATE,
    allowNull: true
  },
  user2DeletedAt: {
    type: db.DATE,
    allowNull: true
  }
}, { 
  timestamps: true,
  // 移除全局paranoid模式,因为我们要自定义用户级删除逻辑
});

module.exports = Conversation;

// 关联关系保持不变
User.hasMany(Conversation, { foreignKey: 'user1' });
User.hasMany(Conversation, { foreignKey: 'user2' });
Conversation.belongsTo(User, { as: 'Creator', foreignKey: 'user1', allowNull: false })
Conversation.belongsTo(User, { as: 'Recipient', foreignKey: 'user2', allowNull: false })

2. 数据库迁移:添加新字段

需要给会话表新增这两个字段,用Sequelize CLI生成迁移文件:

npx sequelize-cli migration:generate --name add-user-deleted-fields-to-conversations

然后在生成的迁移文件中添加字段:

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.addColumn('Conversations', 'user1DeletedAt', {
      type: Sequelize.DATE,
      allowNull: true
    });
    await queryInterface.addColumn('Conversations', 'user2DeletedAt', {
      type: Sequelize.DATE,
      allowNull: true
    });
    // 如果你不再需要全局的deletedAt字段,可以移除它:
    // await queryInterface.removeColumn('Conversations', 'deletedAt');
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.removeColumn('Conversations', 'user1DeletedAt');
    await queryInterface.removeColumn('Conversations', 'user2DeletedAt');
    // 回滚时如果之前删了deletedAt,再加回来:
    // await queryInterface.addColumn('Conversations', 'deletedAt', {
    //   type: Sequelize.DATE,
    //   allowNull: true
    // });
  }
};

运行迁移生效:

npx sequelize-cli db:migrate

3. 修改删除接口:实现用户级软删除

不再调用destroy()(会触发全局软删除),而是根据当前登录用户的身份,更新对应的userXDeletedAt字段:

router.delete("/:id", async(req, res) => {
  const { id } = req.params;
  const currentUserId = req.user.id; // 假设你通过用户认证拿到当前用户ID

  try {
    const conversation = await Conversation.findByPk(id);
    if (!conversation) {
      return res.status(404).send('会话不存在');
    }

    // 判断当前用户是会话的哪一方
    let updateField;
    if (conversation.user1 === currentUserId) {
      updateField = 'user1DeletedAt';
    } else if (conversation.user2 === currentUserId) {
      updateField = 'user2DeletedAt';
    } else {
      // 非会话参与者无权限删除
      return res.status(403).send('你无权删除该会话');
    }

    // 更新对应字段为当前时间(标记为已删除)
    await conversation.update({
      [updateField]: new Date()
    });

    res.status(204).send();
  } catch (error) {
    res.status(500).send(error.message);
  }
});

4. 修改会话查询逻辑:只返回用户未删除的会话

当用户获取自己的会话列表时,需要过滤掉自己标记为已删除的记录。为了简化查询,我们可以给模型添加Scope:

// 在Conversation模型定义中添加scope
const Conversation = db.define("Conversation", {
  // ... 字段定义不变
}, { 
  timestamps: true,
  scopes: {
    // 自定义Scope:返回指定用户可见的活跃会话
    activeForUser(userId) {
      return {
        where: {
          [db.Sequelize.Op.or]: [
            {
              user1: userId,
              user1DeletedAt: null
            },
            {
              user2: userId,
              user2DeletedAt: null
            }
          ]
        }
      };
    }
  }
});

之后查询用户的会话列表就可以直接用这个Scope:

// 示例:获取当前登录用户的所有可见会话
const currentUserId = req.user.id;
const userConversations = await Conversation.scope({ 
  method: ['activeForUser', currentUserId] 
}).findAll({
  include: ['Creator', 'Recipient'] // 关联查询用户信息
});

补充说明

  • 这种方式完全保留了所有会话记录,只是通过用户专属字段控制可见性,符合你"保留会话记录"的需求。
  • 如果需要恢复用户已删除的会话,只需要将对应userXDeletedAt字段设为null即可。
  • 如果你还需要管理员级别的全局删除,可以保留全局deletedAt字段,查询时同时过滤全局删除和用户级删除的记录。

内容的提问来源于stack exchange,提问作者kd12345

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:48:37