(二)Node ORM-Sequelize

528 阅读5分钟

看了上一篇的文章后,会不会很慌,不会写SQL语句怎么办才好,今天分享下前端不写SQL也能操作数据,实现Node,给予Promise 的ORM,支持多种数据库,事务,关联。

安装: npm i sequelize mysql2 -S

会不会发现这个安装的命令很骚,其实是换汤不换药的操作,sequelize在这种做映射,通过mysql2去跟底层数据库进行打交道来实现

实现上一篇的功能的顺序有 建立连接 --> 定义模型 (创建表,声明字段)--> 数据库同步 sync()

const Sequelize = require("sequelize");

//建立连接
const sequelize = new Sequelize("nodetest","root","root",{
    host"localhost",
    dialect'mysql',
    operatorsAliasesfalse
});
//定义模型
const Food = sequelize.define('food',{
    name: Sequelize.STRING(20),
    price: {
        type:Sequelize.FLOAT,
        allowNullfalse
    },
    stock:{
        type:Sequelize.INTEGER,
        defaultValue0
    }
})

//同步模型
Food.sync();

在控制台上打印出我们创建表的SQL语句

基本的sql表已经创建完成了,现在开始往表中添加数据,我们可以在sync中create一个数组数据。 如果这当中修改了配置选项,我们需要重新创建新表,删了旧表,则再sync 设置 {force: true}就行了,才能修改有效。

Fruit.sync({forcetrue}).then(()=>{// force强制同步,表存在更新配置没作用,需要把旧的删除
    //添加数据
    return Fruit.create({name'香蕉',price8.5})
})

如果我们想在创建的水果表中,输出的JSON的水果名称拼接了价格等一些字眼,我们可以在声明字段名称的时候,运用get()进行拼接输出name的名称

name: { //表的字段
        type: Sequelize.STRING(20),
        get(){ //组合
            const name = this.getDataValue('name')
            const price = this.getDataValue('price')
            return `${name}(价格:${price})`
        }
    },
//[{"name":"香蕉(价格:8.5)","id":1,"price":8.5,"stock":200}]

当有时录入的数据中带上了单位,在数据库上是不予许的,这时候我们需要对带上单位的数据进行做处理

//声明的重量字段 stock:{type:Sequelize.INTEGER,defaultValue: 0}
getterMethods: { //将带上单位的数据进行截取去除kg
        amount() {
            return this.getDataValue('stock')+'kg'
        }
     },
setterMethods: {
        amount(val) {
            const idx = val.indexOf('kg');
            const v=val.slice(0,idx)
            this.setDataValue('stock',v)
        }
     }
//数据赋值的时候
fruits[0].amount = '200kg'
fruits[0].save(); //更新

对录入数据时对价格的字段的数据监听,这时候需要进行校验

price: {
        type: Sequelize.FLOAT,
        allowNull:false//不予许为空
        validate: { //检验
            isFloat: {msg'价格字段必须是数字'}, //浮点数
            min: {args: [0],msg'价格字段必须大于0'}
        }
},

现在基本字段需要处理的情况已经阐述了,我们来贴近实际开发中,我们常用到方法

  1. 类型筛选,也是模型拓展的一种,对用户传过来的数据进行过滤出类型
//模型扩展
Fruit.classify = function(name) { //赋值再静态方法上再哪里都可以使用
    const tropicFruits = ['香蕉','芒果']; //如果录入的数据是香蕉或是芒果则热带水果
    return tropicFruits.includes(name) ?'热带水果': '其他水果'
}
//模型拓展测试
const arr =['草莓','aaa']
arr.forEach(f=>{
    console.log(Fruit.classify(f))
}) //其他水果
  1. 运用实例原型的方法,计算出相应的数据信息
//对数量和价格进行计算,在prototype中做实例的拓展
// console.log(Fruit.prototype);
//实例方法是得算出来后才能去调用
Fruit.prototype.totalPrice = function (count) { //从查询中得出实例中的一个方法
    return this.price*count
}
Fruit.findAll().then(fruits => {
    console.log('调用实例计算出来的总价:'+fruits[0].totalPrice(50))
    //一般这种可以运用在提交订单后吧总价格数据返回到前端使用
}
  1. 查询数据对数据库进行筛选数据有:id,条件,操作符查询方法
Fruit.findAll().then(fruits => {
    //最后 数据查询
        //根据id去查
        // Fruit.findById(1).then(fruit => console.log(fruit.get()))
         //根据条件去查where
        // Fruit.findOne({where:{name: '香蕉'}}).then(fruit => console.log(fruit.get()))
        // 查询操作符
        const Op = Sequelize.Op; //具体看下https://segmentfault.com/a/1190000011583806
        Fruit.findAll({
            where: {
                price:{[Op.lt]:5//价格小于5元
            }
        }).then(fruit => console.log(fruits[0].get()))

}
  1. 聚合操作,更新,删除等操作
//聚合 查出表中最突出的,比如价格最高的
        Fruit.max("price"//价格最高
        Fruit.sum('price'//总额

        //2. 更新
        Fruit.update({price:4.66666},{where:{id:1}})

        //删除
        Fruit.destroy({where:{id:2}})

以上都能够在我们开发中应用到,但是异步的处理我们无法在这当中得到谁先谁后的顺序,所以我们在开发中我们还是需要结合到asycn...await ..的方法进行同步化处理 之后我会更新上 没有同步情况的代码文件和同步后的代码文件,同步后的代码文件会实现多数据嵌套的情况,也是我们经常遇到数据结构情况,这种是属于1:N关系,如以下情况