当前位置: 代码迷 >> 综合 >> Sequelize 排序问题:将字符串类型字段转数字类型后进行排序
  详细解决方案

Sequelize 排序问题:将字符串类型字段转数字类型后进行排序

热度:93   发布时间:2024-02-10 04:46:52.0

问题出现场景:

目前使用egg框架进行后端业务开发,使用sequlize这个ORM进行数据库的操作;今天,遇到一个需求,要按照一个被数据库定义为VARCHAR的字段code,按照降序进行排列。

// 原始数据 仅展示 code 字段['999', '2', '11', '23', '300', '856',  '7869', '66', '88', '1234444', '3333']// 理想结果res ->  ['1234444', '7869', '3333', '999', '856', '300', '88', '66', '23', '11', '2']

  我按照常规的处理方法,进行操作,输出的结果,大概是这样的。如下: 

this.ctx.model.xxx.findAndCountAll({offset,limit,order: [['code', 'DESC']],
});// 结果res -> ['999', '88', '856', '7869', '66', '3333', '300', '23', '2', '1234444', '11']

显然,这样的结果不是我们想要的。这样的排序输出,与前端开发中,字符串数组按照ASCII码排序的结果一致。例如:

// 沿用原始数据
const a = ['999', '2', '11', '23', '300', '856',  '7869', '66', '88', '1234444', '3333'];a.reverse(); 
// 执行结果 -> ['999', '88', '856', '7869', '66', '3333', '300', '23', '2', '1234444', '11']

至于mysql中的排序规则,没有去查,原理应该是类似的。到此,其实也找到了问题的所在,就是数字字符串,并没有按照纯数字的规则进行排序,而是按照字符串的规则进行排序,而字符串的排序规则,又是按照ASCII码进行的;

解决方案:

由于不是后端开发,所以遇到这个问题,有点方,也是各种搜百度;

最后确认了三种处理方法:

1、纯sql语句,简单地在要排序的字段后 *1或者 +1即可;

2、纯sql语句,使用MySQL绝对值函数ABS(字段名);

3、纯sql语句,使用ORDER BY CAST(字段名 AS SIGNED);

// 实现 1SELECT * FROM table1 ORDER BY code + 1 DESC;// 实现 2SELECT * FROM table1 ORDER BY code * 1 DESC;// 实现 3SELECT * FROM table1 ORDER BY ABS(code) DESC;// 实现 4SELECT * FROM table1 ORDER BY CAST(code as SIGNED) DESC;

对比以上纯sql的实现,要通过sequelize进行实现的话,好像只有第3种方法可以进行修改;

接下来就是找sequelize中对应的CAST( * as SIGNED) 的方法了;

在sequelize官方文档中,看到的cast()方法,但是type参数并没有罗列对应的枚举值;参考:http://sequelize.org/master/class/lib/sequelize.js~Sequelize.html

然后查mysql对应的方法入参,发现 SIGNED  对应了int类型。所以最终的的sequelize写法如下:

this.ctx.model.table.findAndCountAll({order: [[sequelize.cast(sequelize.col('code'), 'SIGNED'), 'DESC']],
});

这里还有一个坑,如果只是sequelize.cast('code', 'SIGNED')的话,排序是不生效的;只有写成代码块中的写法,才能正常执行;