Sequelize ORM sql 语句工具

Sequelize ORM sql 语句工具

  1. sequelize orm中文网
  2. 视频学习@长乐未央
  3. sql线上练习网址

初始化配置

Sequelize orm 配置文章@落日沉溺于海

  1. 在命令行中全局安装
npm i -g sequelize-cli
  1. sequelize 执行需要匹配 mysql2 对应的依赖(安装 mysql2)
npm i sequelize mysql2
  1. 初始化项目
sequelize init
  1. 熟悉初始化项目后的项目结构
  • config:时配置的意思,这里放的也就是 sequelize 所需要的连接数据库的配置文件
  • migrations:是迁移的意思,如果你需要对数据库做新增表,修改字段,删除表等操作,就需要在这里添加迁移文件了。而不是像以前那样,使用客户端软件直接操作数据库
  • models:这里面存放的模型文件,当我们使用 sequelize 来执行增删改查时,就需要用这里的模型文件了,每个模型都对应数据库中的一张表。
  • seeders:是存放种子文件。一般会将一些需要添加到数据表的测试数据存放在这里。只需要执行一个命令,数据表中就回自动填充进一些用来测试内容的了。
  1. 配置 config.js 文件
  • 第一个要改的就是密码,修改成 docker 配置里,我们设定的密码。接着要改的是数据库的名字,改为 clwy_api_development。
  • 最下面,还要加上时区的配置,因为我们中国是在+8 区。这样在查询的时候,时间才不会出错。
  • 那么同样的,也简单的给 test 和 production 也调整一下。

注意:json 文件中都必须为字符串要不有可能会报错。

  • The “data” argument must be one of type string, TypedArray, or DataView. Received type number (我将password配置为了 number,所以有了这个报错。改成 string 类型即可。)
{
  "development": {
    "username": "root",
    "password": "",
    "database": "yourmysql",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "yourtestmysql",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "yourproductionmysql",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  }
}
  1. 使用 ORM 创建一个表
sequelize model:generate --name Article --attributes title:string,content:text
  1. 运行迁移
sequelize db:migrate
  1. 种子文件
sequelize seed:generate --name article

完成后,在 seeds 目录,就看到刚才命令新建的种子文件了。同样也是分为两个部分,up 部分用来填充数据,down 部分是反向操作,用来删除数据的。

种子文件改写代码如下

async up (queryInterface, Sequelize) {
  const articles = [];
  const counts = 100;

  for (let i = 1; i <= counts; i++) {
    const article = {
      title: `文章的标题 ${i}`,
      content: `文章的内容 ${i}`,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    articles.push(article);
  }

  await queryInterface.bulkInsert('Articles', articles, {});
},
  1. 运行种子
sequelize db:seed --seed xxx-article

sequelize 简化接口封装案例

  1. 在执行完上面操作(创建models,运行种子文件)后,进行下面接口封装

/admin/articles 文件代码

const express = require("express");
const router = express.Router();
const { Article } = require("../../models");
const { Op } = require("sequelize");
const { NotFoundError, success, failure } = require("../../utils/response.js");

/* GET home page. */

router.get("/getArticlesList", async function (req, res, next) {
  try {
    const query = req.query;
    const currentPage = Math.abs(Number(query.currentPage) || 1);
    const pageSize = Math.abs(Number(query.pageSize) || 10);
    /*
     变量定义
          offset 从那一页开始
          limit 查询多少条
          currentPage 当前页码
    分页查询公式
          offset = (currentPage - 1) * limit
    */
    const offset = (currentPage - 1) * pageSize;
    const condition = {
      // order: [["id", "DESC"]], // 根据id 倒序排列。数组套数组 是可以根据多个字段进行排列
      limit: pageSize,
      offset,
    };

    // 根据所传参数进行 模糊查询
    if (query.title) {
      condition.where = {
        title: { [Op.like]: `%${query.title}%` },
      };
    }
    // 查询所有参数
    // const list = await Article.findAll(condition);
    // 根据数量查询
    const { count, rows } = await Article.findAndCountAll(condition);
    success(res, "获取文章列表成功", {
      list: rows,
      pagination: { currentPage, pageSize, totalCount: count },
    });
  } catch (error) {
    failure(res, error);
  }
});

// 创建文章

router.post("/createArticle", async function (req, res, next) {
  // 白名单过滤 ,避免用户乱填 id
  try {
    const body = {
      title: req.body.title,
      content: req.body.content,
    };
    const article = await Article.create(body);
    success(res, "文章创建成功", { article }, 201);
  } catch (error) {
    failure(res, error);
  }
});

// 删除文章

router.delete("/deleteArticle/:id", async function (req, res) {
  try {
    const id = req.params.id;
    // 查询文章 ,看是否存在
    const article = await getArticle(id);

    await article.destroy(id);
    success(res, "删除成功", { id }, 204);
  } catch (error) {
    failure(res, error);
  }
});

// 更新文章

router.put("/updateArticle/:id", async function (req, res) {
  try {
    const id = req.params.id;
    // 查询文章 ,看是否存在
    const article = await getArticle(id);

    // 白名单过滤 ,避免用户乱填 id
    const body = {
      title: req.body.title,
      content: req.body.content,
    };
    await article.update(body);
    success(res, "更新成功", { article }, 204);
  } catch (error) {
    failure(res, error);
  }
});

// 查询数据
async function getArticle(req) {
  const { id } = req.params;
  const article = await Article.findByPk(id);

  if (!article) {
    throw new NotFoundError(`ID:${id}的文章未找到`);
  }
  return article; // 返回数据给中间件,供其他中间件使用。
}

module.exports = router;


/utils 文件夹

/**
 * 自定义 404 错误类
 */

class NotFoundError extends Error {
  constructor(message) {
    super(message);
    this.name = "NotFoundError";
    this.status = 404;
  }
}

function success(res, message, data, code = 200) {
  res.status(code).json({
    status: true,
    message,
    data,
  });
}

// 报错消息封装
function failure(res, error) {
  if (error.name === "SequelizeValidationError") {
    const errors = error.errors.map((item) => item.message);
    return res
      .status(400)
      .json({ status: false, message: "请求参数错误", errors });
  }
  if (error.name === "NotFoundError") {
    return res.status(404).json({
      status: false,
      message: "资源不存在",
      errors: [error.message],
    });
  }
  res
    .status(500)
    .json({ status: false, message: "服务器错误", errors: [error.message] });
}

module.exports = {
  NotFoundError,
  success,
  failure,
};


sequelize 验证表单

  1. 在 model 文件夹中找到对应的数据表的 js 文件
  2. 针对需要验证的 属性,配置 validate 配置项
  3. 相关验证规则@sequelize 中文官网

/models/article.js 文件内容

"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: {
        type: DataTypes.STRING,
        allowNull: false,
        validate: {
          notEmpty: {
            msg: "title 不允许为空",
          },
        },
      },

      content: {
        type: DataTypes.STRING,
        allowNull: true,
        validate: {
          notEmpty: {
            msg: "content 不允许为空",
          },
        },
      },
    },
    {
      sequelize,
      modelName: "Article",
    }
  );
  return Article;
};

sequelize 指令执行相关报错

  1. Unable to resolve sequelize package in C:\Users\ , 无法解析 C:\Users\中的 sequelize 包. 依次执行下面指令
    • npm install sequelize-cli -g
    • sequelize -h ,显示 Unable to resolve sequelize package in C:\Users\
    • npm install --save sequelize

sequelize 报错ERROR: Validation error

  1. 定义一个表时,经常会为某些字段设置唯一性约束(Unique),以确保数据的唯一性。
  2. error: validation error 报错,某个字段可能存在重复值.
  3. 解决办法:
    • 找到设置 Unique(唯一索引) 的字段, 然后在种子文件中,对重复的数据进行整改
  4. 参考文章

sequelize 迁移文件相关使用

迁移运行

  1. 当我们使用 sequelize 创建了数据表之后,会在项目里自动生成 models ,migrations 文件
  2. 生成上述文件后,我们还需使用文件迁移指令,才能在数据库生成上面 对应的数据表
  3. 执行 sequelize db:migrate后,数据库就会生成对应的数据表

迁移回退 (注意:回退之前最好备份一下数据表)

  1. 当我们迁移文件后,发现部分属性不是我们想要的配置后
  2. 执行sequelize db:migrate:undo,就会撤销最近一次的迁移操作.
  3. migratios文件中配置好相关属性后, 就可以 重新执行 sequelize db:migrate 进行文件迁移

sequelize 新增表 练习

注意:

  1. 新增表的属性,多个属性之间使用 逗号隔开.
  1. 新增一张 Category 数据表
sequelize model:generate --name Category --attributes name:string,rank:integer

命令执行后 migrations 文件配置(category)

 async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Categories', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER.UNSIGNED
      },
      name: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      rank: {
        type: Sequelize.INTEGER.UNSIGNED,
        allowNull: false,
        defaultValue: 1
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  1. 新建一张 User 用户表
sequelize model:generate --name User --attributes email:string,username:string,password:string,nick:string,sex:tinyint,company:string,introduce:text,role:tinyint

migrations 文件配置(user)

     async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER.UNSIGNED
      },
      email: {
        allowNull: false,
        type: Sequelize.STRING
      },
      username: {
        allowNull: false,
        type: Sequelize.STRING
      },
      password: {
        allowNull: false,
        type: Sequelize.STRING
      },
      nick: {
        type: Sequelize.STRING
      },
      sex: {
        allowNull: false,
        type: Sequelize.TINYINT
      },
      company: {
        type: Sequelize.STRING
      },
      introduce: {
        type: Sequelize.TEXT
      },
      role: {
        type: Sequelize.TINYINT
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
    await queryInterface.addIndex(
      "Users", {
      fields: ['email'],// 需要索引的属性
      unique: true,// 唯一索引
    }
    );
    await queryInterface.addIndex(
      "Users", {
      fields: ['username'],// 需要索引的属性
      unique: true,// 唯一索引
    }
    );
    await queryInterface.addIndex(
      "Users", {
      fields: ['role'],
    }
    );
  },
  1. 新增一张 Course 课程表
sequelize model:generate --name Course --attributes categoryId:integer,userId:integer,name:string,image:string,recomended:boolean,introductory:boolean,content:text,likesCount:integer,chaptersCount:integer

migrations 文件配置(Course)

  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Courses', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER.UNSIGNED
      },
      categoryId: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      userId: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      name: {
        type: Sequelize.STRING
      },
      image: {
        type: Sequelize.STRING
      },
      recomended: {
        type: Sequelize.BOOLEAN
      },
      introductory: {
        type: Sequelize.BOOLEAN
      },
      content: {
        type: Sequelize.TEXT
      },
      likesCount: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      chaptersCount: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
    await queryInterface.addIndex(
      "Course", {
      fields: ['categoryId'],
    }
    );
    await queryInterface.addIndex(
      "Course", {
      fields: ['userId'],
    }
    );
  },
  1. 新增一张 Chapter 章节表
sequelize model:generate --name Chapter --attributes courseId:integer,title:string,content:text,video:string,rank:integer

migrations 文件配置(Chapter)

  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Chapters', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER.UNSIGNED
      },
      courseId: {
        allowNull: false,
        type: Sequelize.INTEGER
      },
      title: {
        allowNull: false,
        type: Sequelize.STRING
      },
      content: {
        type: Sequelize.TEXT
      },
      video: {
        type: Sequelize.STRING
      },
      rank: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
    await queryInterface.addIndex(
      "Chapters", {
      fields: ['courseId'],
    }
    );
  },
  1. 新增一张 Like 点赞表
sequelize model:generate --name Like --attributes courseId:integer,userId:integer

migrations 文件配置 (Like)

  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Likes', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER.UNSIGNED
      },
      courseId: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      userId: {
        allowNull: false,
        type: Sequelize.INTEGER.UNSIGNED
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
    await queryInterface.addIndex(
      "Likes", {
      fields: ['courseId'],
    }
    );
    await queryInterface.addIndex(
      "Likes", {
      fields: ['userId'],
    }
    );
  },
  1. 新增一张 Setting 系统设置表
sequelize model:generate --name Setting --attributes name:string,icp:string,copyright:string

migrations 文件配置 (Setting)

  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Settings', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER.UNSIGNED
      },
      name: {
        type: Sequelize.STRING
      },
      icp: {
        type: Sequelize.STRING
      },
      copyright: {
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },

sequelize seed(种子文件) 相关使用

生成种子文件

  1. sequelize seed:generate --name [种子文件名称]

运行种子文件

  1. sequelize db:seed --seed [种子文件名称]

配置数据模型 (model,表单验证)

  1. 找到对应的 model 模型文件,对指定属性进行表单验证

生成种子文件练习

  1. 生成 category 种子文件
sequelize seed:generate --name category

category 种子文件 mock 数据

  async up(queryInterface, Sequelize) {
    await queryInterface.bulkInsert('Categories', [
      { name: '前端开发', rank: 1, createdAt: new Date(), updatedAt: new Date() },
      { name: '后端开发', rank: 2, createdAt: new Date(), updatedAt: new Date() },
      { name: '移动端开发', rank: 3, createdAt: new Date(), updatedAt: new Date() },
      { name: '数据库', rank: 4, createdAt: new Date(), updatedAt: new Date() },
      { name: '服务器运维', rank: 1, createdAt: new Date(), updatedAt: new Date() },
      { name: '公共', rank: 6, createdAt: new Date(), updatedAt: new Date() },
    ])
  },

sequelize 接口开发大概步骤

  • 种子填充数据
  • 修改模型(增加验证、增加关联)
  • 复制其他路由文件,进行查找替换
  • 修改白名单和搜索
  • app.js 中添加路由
  • Apifox 测试

sequelize 对已经生成的数据表,进行新增/修改字段

  1. 在我们新建的数据表应已经有大量数据,但是我们又需要对目标数据表进行 新增/修改 字段的操作.
  2. 可以使用 sequelize migration:create 指令,重新生成一个 迁移文件,对目标数据表进行操作

注意:
再执行了新增的迁移文件后,需要到对应的模型文件中,添加新增的 属性/字段.

add-avatar-to-user : 表示给 user 数据表添加 avatar 字段

sequelize migration:create --name add-avatar-to-user

打开add-avatar-to-user 迁移文件,配置如下

  async up(queryInterface, Sequelize) {
    await queryInterface.addColumn('Users', 'avatar', {
      type: Sequelize.STRING
    })
  },

打开 user models 文件,初始化添加 avatar 字段

User.init(
  {
    email: DataTypes.STRING,
    username: DataTypes.STRING,
    password: DataTypes.STRING,
    nick: DataTypes.STRING,
    sex: DataTypes.TINYINT,
    company: DataTypes.STRING,
    introduce: DataTypes.TEXT,
    role: DataTypes.TINYINT,
    // 新增字段后,一定要手动配置一下 新增的字段.否则后续新增/更新操作都找不到 新增的字段.
    avatar: DataTypes.STRING,
  },
  {
    sequelize,
    modelName: "User",
  }
);
return User;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值