NodeJS的sequelize高级关联的用法

3,168 阅读2分钟

这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

预先加载

预先加载是一次查询多个模型的数据的行为,是具有一个或多个 join 的查询

const User = sequelize.define('user', { name: DataTypes.STRING }, { timestamps: false });
const Task = sequelize.define('task', { name: DataTypes.STRING }, { timestamps: false });
const Tool = sequelize.define('tool', {
  name: DataTypes.STRING,
  size: DataTypes.STRING
}, { timestamps: false });
User.hasMany(Task);
Task.belongsTo(User);
User.hasMany(Tool, { as: 'Instruments' });

获取单个关联元素

关联的用户加载所有任务

const tasks = await Task.findAll({ include: User });
console.log(JSON.stringify(tasks, null, 2));

打印结果:

[{
  "name": "A Task",
  "id": 1,
  "userId": 1,
  "user": {
    "name": "张三",
    "id": 1
  }
}]

总结:

关联的模型被添加到名为 user 的新字段中. Sequelize 会根据关联模型的名称自动选择此字段的名称,在适用的情况下(即关联为 hasMany 或 belongsToMany)使用该字段的复数形式

获取所有关联的元素

const users = await User.findAll({ include: Task });\
console.log(JSON.stringify(users, null, 2));

打印结果:

[{
  "name": "张三",
  "id": 1,
  "tasks": [{
    "name": "A Task",
    "id": 1,
    "userId": 1
  }]
}]

关联是一对多的,因此访问器(结果实例中的tasks属性)是复数的

获取别名关联

如果关联是别名的(使用as参数),则在包含模型时必须指定此别名,但可以为对象提供两个选项:model 和 as

const users = await User.findAll({
  include: { model: Tool, as: 'Instruments' }
});
console.log(JSON.stringify(users, null, 2));

打印结果:

[{
  "name": "张三",
  "id": 1,
  "Instruments": [{
    "name": "hammer",
    "id": 1,
    "userId": 1
  }]
}]

也可以指定的关联别名相匹配的字符串

User.findAll({ include: 'Instruments' }); // 也可以正常使用
User.findAll({ include: { association: 'Instruments' } }); // 也可以正常使用

需要预先加载

预先加载时,可以强制查询仅返回具有关联模型的记录,通过 required: true 参数将查询从默认的 OUTER JOIN 转为 INNER JOIN

User.findAll({
  include: {
    model: Task,
    required: true
  }
});

在模型级别的预先加载加入过滤

预先加载时, 可以使用 where 参数过滤关联的模型

User.findAll({
  include: {
    model: Tool,
    as: 'Instruments'
    where: {
      size: {
        [Op.ne]: 'small'
      }
    }
  }
});

模型中应用 WHERE 子句来引用关联模型中的值,可以使用 Sequelize.col 函数

// 查找所有具有至少一项任务的项目,其中 task.state === project.state
Project.findAll({
  include: {
    model: Task,
    where: {
      state: Sequelize.col('project.state')
    }
  }
})

加入复杂的 where 子句

嵌套列的顶级 WHERE 子句, Sequelize 引用嵌套列的方法:'$nested.column$', 可以用于将 where 条件从包含的模型从 ON 条件移动到顶层的 WHERE 子句

User.findAll({
  where: {
    '$Instruments.size$': { [Op.ne]: 'small' }
  },
  include: [{
    model: Tool,
    as: 'Instruments'
  }]
});

使用带有 include 的 findAndCountAll

findAndCountAll 实用功能支持 include. 仅将标记为 required 的 include 项视为 count

User.findAndCountAll({
  include: [
    { model: Profile, required: true }
  ],
  limit: 3
});

因为 Profile 的 include 已设置为 required,它将导致内部联接,并且仅统计具有个人资料的用户,如果从包含中删除 required,则包含和不包含配置文件的用户都将被计数. 在 include 中添加一个 where 子句会自动使它成为 required

User.findAndCountAll({
  include: [
    { model: Profile, where: { active: true } }
  ],
  limit: 3
});

上面的查询只会统计拥有有效个人资料的用户, 因为在 include 中添加 where 子句时,required 会隐式设置为 true