Sequelize ORM 入门

前置

全局安装Sequelize CLI

bash
npm i -g sequelize-cli

在项目目录下安装依赖

bash
pnpm i sequelize mysql2

初始化

Step1.初始化

bash
sequelize init

初始化后,项目目录下会生成四个目录:config, migrations, models, seeders

其中config目录是配置文件,主要用于配置数据库连接,配置分为三个模块,分别对应开发环境(development)、测试环境(test)以及生产环境(production

json
{
  "development": {
    "username": "root",
    "password": "123456",
    "database": "mysql",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  },
  "test": {
    "username": "root",
    "password": "123456",
    "database": "mysql",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": "123456",
    "database": "mysql",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  }
}

migrations 是迁移文件,存放着数据库对应表的字段配置,这些文件用于新增、删除表,以及修改表字段等直接针对表的操作

seeders是种子目录,当我们希望在表中插入默认数据或测试数据时就可以用到种子

Step2.创建模型(和迁移)

bash
sequelize 数据库名:generate --name 表名 --attributes 字段名A:数据类型A,字段名B:数据类型B,……

运行数据库名:generate命令,会生成一个模型文件,以及一个迁移文件,要注意的是,此命令中的表名应是单数,因为在根据迁移文件生成表时,Sequelize会自动在表名后补充一个“s”

注:此命令大小写敏感

运行命令:

bash
sequelize model:generate --name Article --attributes title:string,content:text

之后,会在models文件夹下生成article.js文件,同时在migrations文件夹下生成时间-create-article.js,如20240201001232-create-article.js

迁移文件的形式如下,其中up函数用于建表,down函数用于删表(即db:migrate:undo命令所执行的函数),迁移文件生成后,会自动添加id, createdAt, updatedAt三个字段

javascript
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Articles', { // createTable时自动补充了复数
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      title: {
        type: Sequelize.STRING
      },
      content: {
        type: Sequelize.TEXT
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('Articles');
  }
};

模型文件形式如下,它用于操作数据库

javascript
'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Article extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
    }
  }
  Article.init({
    title: DataTypes.STRING,
    content: DataTypes.TEXT
  }, {
    sequelize,
    modelName: 'Article',
  });
  return Article;
};

Step3.运行迁移

运行sequelize db:migrate命令,Sequelize就会根据迁移文件在数据库中生成对应表,同时它也会自动生成一张SequelizeMeta表,这张表中存放着当前已经运行过哪些迁移,当再次运行迁移时,这些运行过的迁移文件就会被跳过

Step4.种子的创建与运行

运行sequelize seed:generate --name 种子名命令,以创建种子文件,种子名与表名、数据库名等名称并无实际关联,怎么起都可以(请注意可维护性)

命令执行后,会生成时间-种子名.js文件,命名形式与迁移文件相似,生成之后的种子文件内容如下:

javascript
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up (queryInterface, Sequelize) {
    /**
     * Add seed commands here.
     *
     * Example:
     * await queryInterface.bulkInsert('People', [{
     *   name: 'John Doe',
     *   isBetaMember: false
     * }], {});
    */
  },

  async down (queryInterface, Sequelize) {
    /**
     * Add commands to revert seed here.
     *
     * Example:
     * await queryInterface.bulkDelete('People', null, {});
     */
  }
};

up函数用于运行种子,down函数用于撤销种子,这两个函数内容需要自己编写,自动生成的文件只会提供一个标准的格式,不包含任何功能性的代码

以下是一个基础的种子文件:

javascript
"use strict";

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up(queryInterface, Sequelize) {
    const list = [];
    for (let i = 1; i <= 50; i++) {
      let time = new Date();
      list.push({
        name: "Article-" + i,
        mobile: "15122223333",
        createdAt: time,
        updatedAt: time,
      });
    }
    await queryInterface.bulkInsert("Articles", list, {}); // 向Articles表中插入数据
  },

  async down(queryInterface, Sequelize) {
    await queryInterface.bulkDelete("Articles", null, {});
  },
};

写好up函数后,运行sequelize db:seed --seed 种子文件名命令以执行up函数

使用

javascript
const { User } = require("../../models"); // model实例

// Model.create()
await User.create({
    name: '用户名-1',
    mobile: '13612341234',
    createdAt: new Date(),
    updatedAt: new Date()
}

查找器

Sequelize提供了5种查找器,分别是findAll, findAndCountAll, findOne, findByPk, findOrCreate,根据名字不难理解它们的功能。

  • findAll:生成一个标准的 SELECT 查询

    javascript
    let users = await User.findAll({
        where: {
            name: 'User-1',
        },
    });
    
  • findAndCountAll:结合了 findAll 和 count 的便捷方法,在处理分页查询功能时非常有用,它会检索带有 limit 和 offset 的数据,同时也会返回与where匹配的记录总数

    javascript
    let users = await User.findAndCountAll({
        offset: Number((page - 1) * pageSize),
        limit: Number(pageSize),
    });
    
  • findOne:与findAll相似,但只提供检索到的第一个记录

    javascript
    let users = await User.findOne({
        where: {
            id: 11,
        },
    });
    
  • findByPk:按主键检索

    javascript
    let user = await User.findByPk(11);
    
  • findOrCreate:在表中检索,未检索到则创建一条新记录,在这两种情况下,它会返回检索或创建出的实例,和一个指明指示该实例是否已存在的布尔值

    javascript
    const [user, created] = await User.findOrCreate({
      where: { username: 'sdepold' },
      defaults: {
        job: 'Technical Lead JavaScript'
      }
    });
    

参数

javascript
const Sequelize = require("sequelize");
const Op = Sequelize.Op;

let users = await User.findAndCountAll({
    // 条件
    where: {
        id: 2,
        // 使用 AND
        [Op.and]: [
            { id: 12 },
            { name: 'User-1' }
        ],
        // 使用 OR
        [Op.or]: [
            { id: 12 },
            { name: 'User-1' },
            { mobile: ['15166778899', '15100990099'] }
        ],
        // 使用 LIKE
        [Op.like]: [
            { name: 'User-1%'}
        ]
    },
    // 跳过多少条数据
    offset: Number((page - 1) * pageSize),
    // 取多少条数据
    limit: Number(pageSize),
    // 排序
    order: [["id", "asc"]],
});

javascript
await User.update({ name: "Roland" }, {
    where: {
        id: 123
    }
});

javascript
await User.destroy({
    where: {
        id: 123
    }
});