Sequelize关联查询默认按updatedAt排序?能否取消排序?
先逐个回应你的问题:
1. 你的推测是否属实?
不完全准确哦。Sequelize 本身不会默认给 hasMany 关联的 getSections 方法加上 order: [['updatedAt', 'ASC']] 的排序规则。你看到编辑后的 Section 跑到数组末尾,更可能是因为 PostgreSQL 在没有指定明确排序条件时,查询结果的顺序依赖于数据在磁盘上的存储逻辑——PostgreSQL 更新数据时会写入新的行版本,旧版本被标记为失效,当你没指定排序时,数据库返回的顺序是不确定的,刚好出现了编辑后的行排在末尾的情况。
2. 有无简单方法阻止此排序?
其实严格来说,不是“阻止排序”,而是要避免依赖数据库的不确定顺序。最简单的方式就是给查询显式指定一个固定的排序规则,这样不管数据怎么更新,返回的顺序都是稳定的。如果非要让查询完全不指定排序(不推荐,因为结果顺序不可靠),那只要确保你的关联定义和查询调用里都没有设置 order 选项就行,但这种方式无法保证顺序稳定,不建议在业务代码里使用。
3. 如何保持Section原有顺序?是否存在null排序?
要稳定保持 Section 的创建顺序,最可靠的方案是给 Section 模型添加一个专门的排序字段(比如 position 整数字段),而不是依赖所谓的“null排序”——null排序在不同数据库中行为不一致,而且无法稳定维护顺序。
代码示例来了:
第一步:修改Section模型,添加position字段
// Section.js 模型定义 module.exports = (sequelize, DataTypes) => { const Section = sequelize.define('Section', { // 保留你原有的字段,比如 content、title 等 position: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 } }, {}); Section.associate = function(models) { Section.belongsTo(models.Form); }; return Section; };
第二步:创建Form时给关联的Section指定position
// 创建Form并生成4个有序的Section const createForm = async (formData) => { const form = await Form.create(formData); // 给4个Section分别设置position 1-4,对应创建顺序 await Promise.all([ Section.create({ formId: form.id, position: 1, /* 其他Section字段 */ }), Section.create({ formId: form.id, position: 2, /* 其他Section字段 */ }), Section.create({ formId: form.id, position: 3, /* 其他Section字段 */ }), Section.create({ formId: form.id, position: 4, /* 其他Section字段 */ }) ]); return form; };
第三步:设置关联默认排序(一劳永逸)
在Form模型的关联定义里,直接指定按position升序排序,这样每次调用getSections都会自动返回有序的数组:
// Form.js 模型定义 module.exports = (sequelize, DataTypes) => { const Form = sequelize.define('Form', { // 你的Form字段 }, {}); Form.associate = function(models) { Form.hasMany(models.Section, { // 这里设置默认排序,永久生效 order: [['position', 'ASC']] }); }; return Form; };
如果不想全局设置,也可以每次调用getSections时手动指定排序:
const form = await Form.findByPk(yourFormId); const orderedSections = await form.getSections({ order: [['position', 'ASC']] });
备选方案(无需新增字段):
如果暂时不想加position字段,也可以按createdAt排序(因为编辑不会修改创建时间),这样也能保持创建时的顺序:
// 在Form关联里设置 Form.hasMany(models.Section, { order: [['createdAt', 'ASC']] });
但这个方案的局限性是无法支持后续调整Section顺序的需求,所以还是推荐使用position字段的方案。
内容的提问来源于stack exchange,提问作者marly

