一、软删除
1、逻辑
我们先说一下删除到回收站的原理,其实就是在数据库
中增加了一个字段
。如果这个字段没有值
,就表示这是一个正常的数据
。如果这个字段有值了
,就表示它被删除到回收站
了。数据本身其实一直都存在
,只是多了个字段表示是否在回收站中而已。
这种需求在Sequelize中,能非常轻松的实现,标准的术语叫做:软删除。详情可以看官方文档的这一章:传送门
2、实例
现在,我们以文章表
为例,来实现软删除
。做之前,需要先在文章表
中,增加一个字段
,名叫做:deletedAt
,看名字就知道了,这是用来表示什么时候删除
的。如果这字段有值
,那就表示被删到回收站中
了。
2.1、 新建迁移,增加 deletedAt 字段
sequelize migration:create --name add-deleted-at-to-article
修改迁移里的内容
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('Articles', 'deletedAt', {
type: Sequelize.DATE
});
await queryInterface.addIndex(
'Articles', {
fields: ['deletedAt']
});
},
async down(queryInterface, Sequelize) {
await queryInterface.removeColumn('Articles', 'deletedAt');
}
- 增加了
deletedAt
字段,使用的是日期类型。 - 给这个字段增加了索引,因为我们需要经常使用这个字段,用来查询正常的数据,和在回收站中数据。
2.2、运行一下迁移
sequelize db:migrate
2.3、修改模型
Article.init({
// ...
deletedAt: {
type: DataTypes.DATE
}
}, {
sequelize,
paranoid: true,
modelName: 'Article',
});
- 模型的定义里,增加
deletedAt
- 底下,增加
paranoid: true
2.4、测试软删除
接着再调用查询文章列表
的接口,发现列表里
,根本就没有id: 101
的文章
观察下 SQL
,发现指定了,只查deletedAt字段为空 (Null)
的数据。而我们这条数据的deletedAt
字段里有值
,当然就查不到了。
3、查询已删除的数据
现在文章已经被删掉了,在回收站功能模块里,如何才能查询到已被删除的文章呢?方法也很简单,只需要在查询的条件里添加一个paranoid: false
即可。
const condition = {
}
// 查询被软删除的数据
if (query.deleted === 'true') {
condition.paranoid = false;
condition.where.deletedAt = {
[Op.not]: null
}
}
if (query.title) {
}
- 到
condition
的下面,先判断一下,如果用户传递了deleted=true
参数,那就表明当前要显示的是回收站中的数据。 - 加上
paranoid = false
,这样查询到的数据,除了正常数据外,还会包含被软删除的数据。 - 但我们这里要实现只查询被软删除的数据,正常数据不要。所以在
where
里,还要排除掉deletedAt不为null的数据
。这样查到的数据,就只有被软删除的了。
二、多选批量删除
刚才我们实现了单条文章记录
的软删除
。如果要删除多篇记录
,应该怎么办呢?方法也很简单,让前端传递过来一个数组就行
了,里面包含所有要删除的文章 ID
。
删除与多选批量删除,其实没有必要写两个接口,就公用一个最好了。我们将之前写的删除文章接口,直接删掉,改为:
/**
* 删除到回收站
* POST /admin/articles/delete
*/
router.post('/delete', async function (req, res) {
try {
const { id } = req.body;
await Article.destroy({ where: { id: id } });
success(res, '已删除到回收站。');
} catch (error) {
failure(res, error);
}
});
- 需要注意的是,因为要传递数组过来,这里用
DELETE
请求就不合适了。Express默认不会解析DELETE请求中的body
,所以我们改为POST
请求。 - 接受到用户传递的所有文章 ID 后,直接丢到
where
里,调用destroy
方法删掉即可。 - 这里的
ID
,可以是单条记录值
,也可以是数组
。
三、彻底删除
回收站
里的数据,如果确实不想要了
,要彻底删除掉,又该怎么做的呢?Sequelize也给我们安排好了,删除的时候,传递force: true
就能实现了。
我们现在完成彻底删除文章接口,当然也同时支持彻底删除单条和多条记录。
/**
* 彻底删除
* POST /admin/articles/force_delete
*/
router.post('/force_delete', async function (req, res,) {
try {
const { id } = req.body;
await Article.destroy({
where: { id: id },
force: true
});
success(res, '已彻底删除。');
} catch (error) {
failure(res, error);
}
});
四、恢复/批量恢复
既然能删除到回收站
,那对应的就得有恢复功能
。恢复功能
,同样的可以恢复单条记录
,也能批量恢复多条记录
。
Seqelize已经帮我们准备好了恢复方法,就是 restore
方法,下面来看代码。
/**
* 从回收站恢复
* POST /admin/articles/restore
*/
router.post('/restore', async function (req, res) {
try {
const { id } = req.body;
await Article.restore({ where: { id: id } });
success(res, '已恢复成功。')
} catch (error) {
failure(res, error);
}
});
总结
- 在
Sequelize
里,实现软删除
是非常容易的事情。 数据库
中要增加deletedAt
字段,来记录当前文章是否被删除。模型
里,要添加paranoid: true
。- 现在再删除文章,就会变成
软删除
了。 - 原理就是在
deletedAt字段添加了个时间
而已。 - 在查的时候,我们只查
deletedAt字段为空
的记录。用户就以为数据被删掉
了,其实并没有。 - 要查询
被软删除的记录
,需要添加paranoid: false
。 - 从回收站
恢复数据
,可以用restore
方法。 - 要彻底删掉记录,可以在删除时,传递
force: true
参数。 - 还有一个值得思考的地方是,很多项目都有删除用户的功能。但是
用户往往关联了大量的数据,特别是涉及到了支付相关的项目
。如果真的把用户删掉了
,那么将来追踪订单都会变的困难
。这种情况下,考虑使用软删除
,也是一种解决办法。