Sequelize JS查询PostgreSQL如何扁平化嵌套关联响应
Sequelize关联查询无嵌套扁平化返回方案
不需要使用map遍历二次处理结果,也不需要忍受raw: true带来的字段前缀问题,通过Sequelize原生查询配置即可直接实现你要的返回结构,核心逻辑是把所有需要的关联表字段直接定义在主模型的查询属性中,不在关联模型层配置返回字段。
具体修改步骤
- 把原本写在
include[0].attributes.include里的所有video相关字段,全部挪到主模型user_bookmark的attributes配置中,通过Sequelize.col引用关联表字段,配置好对应别名 - 关联模型
video的attributes设置为空数组,避免Sequelize默认查询关联表字段生成嵌套对象 - 给关联配置添加
duplicating: false标记(适用于当前1对1关联场景,避免生成冗余的JOIN逻辑) - 不需要开启
raw: true,Sequelize会自动把主模型attributes中定义的所有字段直接返回到结果项的顶层,无额外嵌套
修改后的完整查询代码如下:
var video_attributes = [ [sequelize.cast(sequelize.fn("like_count", Sequelize.col("video.id")), 'integer'), "total_likes"], [Sequelize.col("video.id"), "id"] ]; if (request.user) { video_attributes.push([sequelize.fn("has_liked", request.user.id, Sequelize.col("video.id")), "is_liked"]); video_attributes.push([sequelize.fn("has_bookmarked", request.user.id, Sequelize.col("video.id")), "is_bookmarked"]); } mod_idx.user_bookmark.findAll({ where: {"user_id": request.user.id}, include : [{ model: mod_idx.video, as: "video", attributes: [], duplicating: false }], attributes: video_attributes, order: [[ "id", "desc" ]], }).then(video_list => { let r = { "data": video_list, "success": true } response.status(200).json(r) }).catch(function (err) { console.log(err) });
方案说明
- 该方案的所有字段映射逻辑在SQL生成层完成,没有额外的JS层结果遍历处理开销,和原生SQL查询单表的性能完全一致,大批量数据场景下不会产生额外性能损耗
- 此前使用
raw: true出现video.字段前缀,本质是字段定义在关联模型属性下时,Sequelize会自动给嵌套字段加表别名前缀,字段挪到主模型属性层后就不会出现该问题 - 如果需要排除主模型
user_bookmark的其他字段,直接在主模型attributes里配置exclude即可,不会影响顶层字段的映射结果
内容的提问来源于stack exchange,提问作者HarshIT
相关产品推荐
相关产品推荐

