Sequelize 踩坑记录

Sequelize 注释版入门代码样例:https://github.com/kasora/fakeCode/tree/master/sequelize

目录

  1. 查询 join 进来的字段
  2. is not associated with 问题
  3. 同时使用 GROUP BY、DISTINCT 和 COUNT 的 BUG
  4. 利用某一字段更新另一字段
  5. 以 join 进来的字段进行排序

约定规范。

sequelize 提供了很多顶级方法。一般格式为 sequelize.xxx() 其中的 sequelize 指代 new Sequelize 时生成的对象。


———-2017/08/18———-

在查询中如果需要检索 include 引入的新表中的字段时,使用’$includedTable.fieldName$’来检索。

例如

// 建表
let User = sequelize.define('user',
  {
    name: Sequelize.STRING,
    text: Sequelize.STRING(500),
    password: Sequelize.STRING
  }
);
let Work = sequelize.define('work',
  {
    name: Sequelize.STRING,
    userId: Sequelize.INTEGER,
    type: Sequelize.STRING
  }
);

// 建立连接
await User.sync({ force: true });
await Work.sync({ force: true });
await Work.belongsTo(User, { as: 'user', foreignKey: 'userId' });

// 插入样例数据
let kasoraInfo = await User.create({ name: 'kasora', password: 'hello-kasora' });
await Work.create({ type: 'chicken', userId: kasoraInfo.id, name: 'kasora-work' });
let ntzyzInfo = await User.create({ name: 'ntzyz', password: 'hello-ntzyz' });
await Work.create({ type: 'dragon', userId: ntzyzInfo.id, name: 'ntzyz-work' });

// 检索
let userInfo = await Work.findAll({
  where: { '$user.name$': 'kasora' },
  include: [{
    model: User,
    as: 'user'
  }]
});

console.log(userInfo.length) // 1

 


———-2017/08/21———-
is not associated with 问题。常见于查询并使用 include 的情况。

例如:

(node:96247) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: tablea (tablea) is not associated to tableb!

该问题是由于定义连接时别名与 include 时别名不同。

解决方案:

  • 在 belongsTo (或其他设置连接函数)与 include 时的 as 参数填写相同的别名。
  • 在 belongsTo (或其他设置连接函数)与 include 时均不添加 as 参数。

参考:https://itbilu.com/nodejs/npm/41dDJj7n-.html


———-2017/08/30———-

同时使用 GROUP BY、DISTINCT 和 COUNT 时返回值为 Promise<integer> 而不是 Promise<Array<KeyValuePair<field , integer>>>

以下为样例代码:

let Log = sequelize.define('log',
  {
    logType: Sequelize.INTEGER,
    text: Sequelize.STRING
  }
);

let initDB = async () => {
  await Log.sync({ force: true });
};

let insertLog = async () => {
  await Log.create({ text: 'text1', logType: 0 });
  await Log.create({ text: 'text1', logType: 0 });
  await Log.create({ text: 'text2', logType: 1 });
  await Log.create({ text: 'text3', logType: 1 });
};

let start = async () => {
  await initDB();
  await insertLog();

  let query = {
    attributes:['logType'],
    where: {},
    distinct: true,
    group: 'logType',
    logging: true
  }
  let ans = await Log.aggregate('text', 'count', query);
  console.log(ans);
  expect(ans).to.be.an('array');
};

start();

该问题目前暂时原因未知,暂时的解决方案是使用 sequelize.query 直接手动拼接 SQL 来解决

已发 issue,不过。。可能是我英语水平太差写的东西官方看不懂。。所以暂时没有回应。如有回应。会更新本条消息。


———-2017/09/02———-

利用同一记录中的某一字段更新另一字段。

例如在 sql 语句中存在这样的写法

UPDATE tablea SET a = a + b;

但是 sequelize 中如果你写成

tablea.update(
  {
    a: a + b
  }
)

这样的形式的话,sequelize 会尝试将 a 与 b 作为 js 的变量进行解析。当然就报错了。

在官方的 issue 中发现有一个顶级方法 sequelize.col 该方法允许传入一个字符串,来指定引入该字段的值。例如

tablea.update(
  {
    a: sequelize.col('tablea.a')
  }
)

但是如果你尝试对该方法引入的字段进行修改的话,最终就会生成一个 NaN。所以,这个顶级函数实际上只会被用在 where 等查询语句中。

最终在文档中发现了另一个顶级方法 sequelize.literal。

该方法的作用就是,写入一段不会经过转译的字符串作为参数。最终曲线救国。

tablea.update(
  {
    a: sequelize.literal('a + b')
  }
)

———-2017/11/29———-

业务逻辑中,我们经常会使用 tableA include tableB,如果后续的业务需要对结果集以 tableB 中的字段为基准进行排序对 sequelize 来说就是一个很怪异的操作。

实现代码如下:

tableA.findAll({
  include: [{ model: tableB, as: 'tableB' }],
  order: [[{ model: tableB, as: 'tableB' }, 'fieldName']]
});

当然如果没有设置 model 的 as 属性就可以写的简单一些

tableA.findAll({
  include: [{ model: tableB }],
  order: [[tableB, 'fieldName', 'desc']]
});

同时,如果你是嵌套 include 的话,可以写成

tableA.findAll({
  include: [{ model: tableB, include:[{ model: tableC }]}],
  order: [[tableB, tableC, 'fieldName', 'desc']]
});

这时的 order by 字段则会使用 tableB.tableC.fieldName。


———-2018/10/25———-

model 同步的时候需要注意先后顺序。顺序应该为

  1. model 定义
  2. 添加 model 间的关系
  3. model sync

model 不定义则关系没法添加,而添加关系的方法是同步的,也就是说所有的关系都会留到 sync 的时候反馈给数据库。

顺序关系在使用 through 创建中间表和允许 sequelize 修改表结构时相当重要。

但是如果你手动维护数据库关系,那么优先同步 model,再添加关系可以提高加载速度。

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据