Leon's blog Leon's blog
首页
前端
场景
技术
更多
关于
收藏
索引
GitHub (opens new window)

Leon Yu

做一个有个性的开发者~
首页
前端
场景
技术
更多
关于
收藏
索引
GitHub (opens new window)
  • 技术
  • TypeScript

  • NodeJS

    • sequelize学习
      • 使用postman进行服务端开发
    • shell

    • vscode开发

    • 图解HTTP阅读

    • 计算机网络

    • 技术
    • NodeJS
    leon yu
    2024-06-14
    目录

    sequelize学习

    提示

    在写 egg.js 项目时发现自己对于 sequelize 还不太熟悉,于是打算看着官方文档学习一下 Sequelize官方文档 (opens new window)

    # 学习目标

    学习 sequelize 主要为了使用,因此主要关注应用方面。

    # 在数据库中定义模型

    • sequelize.define(modelName, attributes, options) 调用实例的 define 方法可以将对应的模型加入到 sequelize 中,绑定为 sequelize.models[modelName]。
    const { Sequelize, DataTypes } = require('sequelize');
    const sequelize = new Sequelize('sqlite::memory:');
    
    const User = sequelize.define('User', {
      // 在这里定义模型属性
      firstName: {
        type: DataTypes.STRING,
        allowNull: false
      },
      lastName: {
        type: DataTypes.STRING
        // allowNull 默认为 true
      }
    }, {
      // 这是其他模型参数
    });
    
    // `sequelize.define` 会返回模型
    console.log(User === sequelize.models.User); // true
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    • 首先继承 Model ,并调用父类的 init 方法来定义
    const { Sequelize, DataTypes, Model } = require('sequelize');
    const sequelize = new Sequelize('sqlite::memory:');
    
    class User extends Model {}
    
    User.init({
      // 在这里定义模型属性
      firstName: {
        type: DataTypes.STRING,
        allowNull: false
      },
      lastName: {
        type: DataTypes.STRING
        // allowNull 默认为 true
      }
    }, {
      // 这是其他模型参数
      sequelize, // 我们需要传递连接实例
      modelName: 'User' // 我们需要选择模型名称
    });
    
    // 定义的模型是类本身
    console.log(User === sequelize.models.User); // true
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    • 两种方法实际上是共用一个方法,是等效的

    # 根据模型创建实例,向表中加入新数据

    • 完整流程 build + save
      • build 是少数非异步的方法,大部分方法都是异步的
    const jane = User.build({ name: "Jane" });
    console.log(jane instanceof User); // true
    console.log(jane.name); // "Jane"
    
    await jane.save();
    console.log('Jane 已保存到数据库!');
    
    1
    2
    3
    4
    5
    6
    • 快捷流程 create
    const jane = await User.create({ name: "Jane" });
    // Jane 现在存在于数据库中!
    console.log(jane instanceof User); // true
    console.log(jane.name); // "Jane"
    
    1
    2
    3
    4
    • 更新实例:create后使用set更新实例,之后进行保存
    • 删除实例:create后使用destroy销毁实例
    • 重载实例:create后使用reload可以获取数据库中的最新记录
    • 保存实例:保存时可以指定fields来指定仅保留部分字段
    • 使用 increment 和 decrement 方法可以解决递增和递减时的并发问题

    # 基础查询

    # INSERT
    • 使用 create 方法即可插入新数据
    const user = await User.create({
      username: 'alice123',
      isAdmin: true
    }, { fields: ['username'] }); // 在这里可以读取哪些字段,其他的调用为默认值,但是实际作用应该不大
    // 假设 isAdmin 的默认值为 false
    console.log(user.username); // 'alice123'
    console.log(user.isAdmin); // false
    
    1
    2
    3
    4
    5
    6
    7
    # SELECT
    • 使用 findAll() 查询一个表中的所有字段,等价于 SELECT * FROM TABLE_NAME
    • 加入 attributes 属性,可以查询表中的对应字段,attributes 一定要为数组,等价于 SELECT attribute1, attribute2, ... FROM TABLE_NAME
      • 在数组中嵌套数组表示重命名
    Model.findAll({
      attributes: ['foo', ['bar', 'baz'], 'qux']
    });
    
    1
    2
    3
    SELECT foo, bar AS baz, qux FROM ...
    
    1
    • attributes 中可以加入聚合属性,聚合属性必须要有对应的别名
    Model.findAll({
      attributes: [
        'foo',
        [sequelize.fn('COUNT', sequelize.col('hats')), 'n_hats'],
        'bar'
      ]
    });
    
    1
    2
    3
    4
    5
    6
    7
    SELECT foo, COUNT(hats) AS n_hats, bar FROM ...
    
    1
    • 只想添加聚合时,可以使用 include 属性

    • 想要排除某些字段时,可以使用 exclude 属性

    • where 可以传递查询条件,默认为相等,为 [Op.eq]

    • 除此之外,sequelize的Op属性中还有非常多的操作符,具体使用时可以关注模型查询(基础) (opens new window)

    # UPDATE

    第一个参数传递要修改的值,第二个参数可以传递一些选项,比如 where 和 transaction

    // 将所有没有姓氏的人更改为 "Doe"
    await User.update({ lastName: "Doe" }, {
      where: {
        lastName: null
      }
    });
    
    1
    2
    3
    4
    5
    6
    # DELETE
    • 根据条件删除可以传入 where
    • 删除所有条目可以使用 truncate
    // 截断表格
    await User.destroy({
      truncate: true
    });
    
    1
    2
    3
    4
    # 批量创建

    Model.bulkCreate 允许在一次查询中创建多个记录,可以在 bulkCreate 方法中添加参数 validate 来为每个对象进行检验,但是只有所有都通过之后才会创建成功

    const Foo = sequelize.define('foo', {
      name: {
        type: DataTypes.TEXT,
        validate: {
          len: [4, 6]
        }
      }
    });
    
    // 这不会引发错误,两个实例都将被创建
    await Foo.bulkCreate([
      { name: 'abc123' },
      { name: 'name too long' }
    ]);
    
    // 这将引发错误,不会创建任何内容
    await Foo.bulkCreate([
      { name: 'abc123' },
      { name: 'name too long' }
    ], { validate: true });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    • 同时 bulkCreate 也可以加入 fields 参数
    # 排序

    向查询中添加 order 可以选择对应的排序方式

    Subtask.findAll({
      order: [
        // 将转义 title 并针对有效方向列表进行降序排列
        ['title', 'DESC'],
    
        // 将按最大年龄进行升序排序
        sequelize.fn('max', sequelize.col('age')),
    
        // 将按最大年龄进行降序排序
        [sequelize.fn('max', sequelize.col('age')), 'DESC'],
    
        // 将按 otherfunction(`col1`, 12, 'lalala') 进行降序排序
        [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'],
    
        // 将使用模型名称作为关联名称按关联模型的 createdAt 排序.
        [Task, 'createdAt', 'DESC'],
    
        // 将使用模型名称作为关联名称通过关联模型的 createdAt 排序.
        [Task, Project, 'createdAt', 'DESC'],
    
        // 将使用关联名称按关联模型的 createdAt 排序.
        ['Task', 'createdAt', 'DESC'],
    
        // 将使用关联的名称按嵌套的关联模型的 createdAt 排序.
        ['Task', 'Project', 'createdAt', 'DESC'],
    
        // 将使用关联对象按关联模型的 createdAt 排序. (首选方法)
        [Subtask.associations.Task, 'createdAt', 'DESC'],
    
        // 将使用关联对象按嵌套关联模型的 createdAt 排序. (首选方法)
        [Subtask.associations.Task, Task.associations.Project, 'createdAt', 'DESC'],
    
        // 将使用简单的关联对象按关联模型的 createdAt 排序.
        [{model: Task, as: 'Task'}, 'createdAt', 'DESC'],
    
        // 将由嵌套关联模型的 createdAt 简单关联对象排序.
        [{model: Task, as: 'Task'}, {model: Project, as: 'Project'}, 'createdAt', 'DESC']
      ],
    
      // 将按最大年龄降序排列
      order: sequelize.literal('max(age) DESC'),
    
      // 如果忽略方向,则默认升序,将按最大年龄升序排序
      order: sequelize.fn('max', sequelize.col('age')),
    
      // 如果省略方向,则默认升序, 将按年龄升序排列
      order: sequelize.col('age'),
    
      // 将根据方言随机排序(但不是 fn('RAND') 或 fn('RANDOM'))
      order: sequelize.random()
    });
    
    Foo.findOne({
      order: [
        // 将返回 `name`
        ['name'],
        // 将返回 `username` DESC
        ['username', 'DESC'],
        // 将返回 max(`age`)
        sequelize.fn('max', sequelize.col('age')),
        // 将返回 max(`age`) DESC
        [sequelize.fn('max', sequelize.col('age')), 'DESC'],
        // 将返回 otherfunction(`col1`, 12, 'lalala') DESC
        [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'],
        // 将返回 otherfunction(awesomefunction(`col`)) DESC, 这种嵌套可能是无限的!
        [sequelize.fn('otherfunction', sequelize.fn('awesomefunction', sequelize.col('col'))), 'DESC']
      ]
    });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68

    回顾一下,order 数组的元素可以如下: 一个字符串 (它将被自动引用), 一个数组, 其第一个元素将被引用,第二个将被逐字追加, 一个具有 raw 字段的对象:raw 内容将不加引用地逐字添加,其他所有内容都将被忽略,如果未设置 raw,查询将失败 调用 Sequelize.fn (这将在 SQL 中生成一个函数调用), 调用 Sequelize.col (这将引用列名),

    # 分组

    分组和排序的语法几乎一样,但是没有升序和降序之别

    注意

    你还可以将字符串直接传递给 group,该字符串将直接(普通)包含在生成的 SQL 中. 请谨慎使用,请勿与用户生成的内容一起使用.

    # 限制与分页

    在查询中,加入 limit 可以限制查询的最多数目,加入 offset 可以声明开始查询的条目

    # 实用方法
    • count 计算数据库中元素出现的数目
    console.log(`这有 ${await Project.count()} 个项目`);
    
    const amount = await Project.count({
      where: {
        id: {
          [Op.gt]: 25
        }
      }
    });
    console.log(`这有 ${amount} 个项目 id 大于 25`);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    • max min sum
    await User.max('age'); // 40
    await User.max('age', { where: { age: { [Op.lt]: 20 } } }); // 10
    await User.min('age'); // 5
    await User.min('age', { where: { age: { [Op.gt]: 5 } } }); // 10
    await User.sum('age'); // 55
    await User.sum('age', { where: { age: { [Op.gt]: 5 } } }); // 50
    
    1
    2
    3
    4
    5
    6
    • increment,decrement (前面已有)

    # 模型查找器

    • findAll 查询所有条目
    • findByPk 根据主键进行查找
    • findOne 查找满足条件的第一个条目
    • findOrCreate 除非找到一个满足查询参数的结果,否则方法 findOrCreate 将在表中创建一个条目. 在这两种情况下,它将返回一个实例(找到的实例或创建的实例)和一个布尔值,指示该实例是已创建还是已经存在.

    提示

    使用 where 参数来查找条目,而使用 defaults 参数来定义必须创建的内容. 如果 defaults 不包含每一列的值,则 Sequelize 将采用 where 的值(如果存在). 假设我们有一个空的数据库,该数据库具有一个 User 模型,该模型具有一个 username 和一个 job.

    const [user, created] = await User.findOrCreate({
      where: { username: 'sdepold' },
      defaults: {
        job: 'Technical Lead JavaScript'
      }
    });
    console.log(user.username); // 'sdepold'
    console.log(user.job); // 这可能是也可能不是 'Technical Lead JavaScript'
    console.log(created); // 指示此实例是否刚刚创建的布尔值
    if (created) {
      console.log(user.job); // 这里肯定是 'Technical Lead JavaScript'
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    • findAndCountAll 结合了 findAll 和 count 的便捷方法. 在处理与分页有关的查询时非常有用,在分页中,你想检索带有 limit 和 offset 的数据,但又需要知道与查询匹配的记录总数.

    提示

    当提供了 group 时, findAndCountAll 方法返回一个具有两个属性的对象:

    count - 一个数组对象 - 包含每组中的合计和预设属性 rows - 一个数组对象 - 获得的记录

    提示

    至此,已经基本学习了 sequelize 的基本语法,剩下的内容更适合阅读学习,只有遇到场景时才需要查阅。

    最近更新~: 2024/08/19, 01:05:55
    教程中的难点3
    使用postman进行服务端开发

    ← 教程中的难点3 使用postman进行服务端开发→

    最近更新
    01
    应用层
    01-11
    02
    计算机网络和因特网
    12-22
    03
    关于
    12-22
    更多文章>
    Theme by Vdoing | Copyright © 2024-2025 主题来自 Evan Xu | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式