Sequelize 嵌套模型查询及嵌套模型字段排序

 2018年03月16日    1062     声明


Sequelize 的“嵌套模型查询”最终会生成SQL“连接查询”语句,即生成'inner join''left join'等。在连接查询时,我们在可以连接阶段通过'on ... and'(如:ON A.id = B.user_id AND B.name = 'itbilu.com')来对连接表进行筛选,可以在where条件中(如:WHERE B.name = 'itbilu.com')进行筛选。除数据筛选外,结果排序也会经常用到。在SQL语句中,对连接表排序比较简单,直接把连接表的排序字段放到order by子语句中即可(如:'ORDER BY B.name ASC')。在Sequelize中,同样也可以支持连接模型的筛选和排序。以下是Sequelize中连接模型的筛选与排序的使用小技巧。

  1. Sequelize 与连接模型的筛选
  2. Sequelize 与连接模型的排序

1. Sequelize 与连接模型的筛选

Sequelize 通过'include'属性来生成连接查询语句,对连接模型(连接表)数据进行筛选时,我们可以将筛选条件放在'include'连接模型的'where'属性中,也可以放在顶级'where'属性中。


连接模型'where'

我们有如下两个模型,并在连接模型中使用'where'属性:

const User = sequelize.define('user', 
  { id: Sequelize.INT,
    account: Sequelize.STRING,
    password: Sequelize.STRING
  });
const Player = sequelize.define('player', 
  { id: Sequelize.INT,
    userId: Sequelize.INT,
    name: Sequelize.STRING
  });
User.hasOne(Player);

let include = [{
  model: Player,
  where: {name:'itbilu.com'}
}];
User.findAll({ include: include }).then((users) => {
  console.log(JSON.stringify(users))
})

以上查询会生成类似如下SQL语句:

SELECT * FROM user INNER JOIN player ON user.id = player.userId AND player.name = 'itbilu.com';


顶级'where'

我们也可以将'on'中筛选条件放到顶级'where'属性中。在顶级'where'中,使用'$nested.column$'语法格式进行连接模型(连接表)的数据筛选。

同样是

let include = [{
  model: Player,
  where: {name:'itbilu.com'}
}];
User.findAll({ where: {'$player.name$':'itbilu.com'}, include: include }).then((users) => {
  console.log(JSON.stringify(users))
})

以上查询会生成类似如下SQL语句:

SELECT * FROM user INNER JOIN player user.id = player.userId where player.name = 'itbilu.com';


由上可见,在连接模型的'where'属性中进行筛选时,最终生成的SQL语句会在'ON'条件中进行筛选。也就是说,数据筛选是在表连接之前;而在顶级'where'属性中进行筛选时,最终生成的SQL语句会在'WHERE'条件中进行筛选,也就是说,的筛选在表连接之后。一般来说,前者的执行效率要高于后者。


2. Sequelize 与连接模型的排序

在Sequelize中,通过'order'属性生成'ORDER BY'排序SQL。'order'属性支持字符串格式:

User.findAll({order:'id DESC'});

也支持数组(二维数组)格式:

User.findAll({order:[['id', DESC]]});

如果使用连接模型字段排序,就要向排序数组中传入3个值:

User.findAll({ include:[ Player ], order:[[Player, 'id', DESC]]});

如果有更多级的嵌套,就要向排序数组中传入更多的值:

const PlayerLevel = sequelize.define('playerLevel',  
  { id: Sequelize.INT,
    playerId: Sequelize.INT,
    level: Sequelize.INT
  })
Player.hasOne(PlayerLevel);

let include = [{
  model: Player,
  include: [PlayerLevel]
}];
User.findAll({ include:include, order:[[Player, PlayerLevel, 'level', DESC]]});

以上生成的排序语句类似如下:

ORDER BY player.playerLevel.level DESC

或者,使用sequelize.col()函数来处理多级嵌套。以上查询等价于:

User.findAll({ include:include, order:[[sequelize.col('player.playerLevel.level'), DESC]]});


更多参考: