使用Sequelize操作MySQL

Sequelize ORM 實(shí)踐

由于sequelize依賴于mysql2所以也需要安裝mysql2:
npm install mysql2 --save
創(chuàng)建數(shù)據(jù)庫:
字符集:utf8mb4
排序規(guī)則:utf8mb4_genaral_ci
字段數(shù)據(jù)類型:

字段數(shù)據(jù)類型

const {Sequelize,Model} = require('sequelize')
const {unset, clone, isArray} = require('lodash')
const {
    dbName,
    host,
    port,
    user,
    password
} = require('../config/config1').database

const sequelize = new Sequelize(dbName,user,password,{
    dialect:'mysql',
    host,
    port,
    logging:true,
  
    timezone: '+08:00',
    // 個性化配置
    define:{
        //create_time  update_time delete_time
        timestamps:true,
        paranoid:true, // 開啟軟刪除
        createdAt:'created_at',  // 自定義字段名磺陡,默認(rèn)為'createdAt'脚线,將其改為'created_at'
        updatedAt:'updated_at',
        deletedAt:'deleted_at',
        underscored:true,  // 字段駝峰轉(zhuǎn)下劃線
        // 禁止修改表名略荡,默認(rèn)情況下丑孩,sequelize將自動將所有傳遞的模型名稱(define的第一個參數(shù))轉(zhuǎn)換為復(fù)數(shù)
        // 但是為了安全著想摄悯,復(fù)數(shù)的轉(zhuǎn)換可能會發(fā)生變化朽缎,所以禁止該行為
        freezeTableName:true,
        scopes:{
            bh:{ // 過濾不必要的字段(這里會有bug)
                attributes:{
                    exclude:['updated_at','deleted_at','created_at']
                }
            }
        }
    }
})

sequelize.sync({
    force:false  // true 清空數(shù)據(jù)庫表
})

Model.prototype.toJSON= function(){
    // let data = this.dataValues
    let data = clone(this.dataValues)
    unset(data, 'updated_at')
    unset(data, 'created_at')
    unset(data, 'deleted_at')

    for (key in data){
        if(key === 'image'){
            if(!data[key].startsWith('http'))
                data[key]=global.config.host + data[key]
        }
    }

    if(isArray(this.exclude)){
        this.exclude.forEach(
            (value)=>{
                unset(data,value)
            }
        )
    }
    // this.exclude
    // exclude
    // a,b,c,d,e
    return data
}

module.exports = {
    sequelize
}

數(shù)字類型查詢比字符串查詢快


Sequelize 中文API文檔-5. 實(shí)例的使用稠集、Instance類介紹:
  • findOne:
async validateEmail(vals) {
        const email = vals.body.email
        const user = await User.findOne({
            where: {
                email: email
            }
        })
        if (user) {
            throw new Error('email已存在')
        }
    }
  • setDataValue:
static _getEachBookStatus(book, favors){
        let count = 0
        favors.forEach(favor=>{
            if(book.id === favor.art_id){
                count = favor.get('count')
            }
        })
        book.setDataValue('fav_nums',count)
        return book
    }
  • count:
 static async getMyFavorBookCount(uid) {
        const count = await Favor.count({
            where: {
                type: 400,
                uid
            }
        })
        return count
    }

increment
decrement

static async getAll(){
        const books =await HotBook.findAll({
            // 排序
            order:[
                'index'
            ]
        })
        const ids = []
        books.forEach((book)=>{
            ids.push(book.id)
        })
        const favors =await Favor.findAll({
            where:{
                art_id:{
                    [Op.in]:ids,
                },
                type:400
            },
            group:['art_id'], // 排序
            attributes:['art_id', [Sequelize.fn('COUNT','*'),'count']]
        })
        books.forEach(book=>{
             HotBook._getEachBookStatus(book, favors)
        })
        //python 二維矩陣
        return books
    }

linvalidator:

module-alias別名包

lin-cms 不能攔截sequelize的錯誤翘魄?鼎天??
Unhandled rejection SequelizeValidationError: string violation: banner cannot be an array or an object
Unhandled rejection SequelizeDatabaseError: Unknown column 'place_orders_nums' in 'field list'

class ProductDao {
  async createGoods (v) {
    /** 這里需要創(chuàng)建多個表
     * 1:商品表
     * 2:規(guī)格值表
     * 3:商品和規(guī)格關(guān)系表
     * 4:sku表
     * 創(chuàng)建商品 */
    const goods = new Product();
    goods.name = v.get('body.name');
    goods.banner = v.get('body.banner');
    goods.desc_imgs = v.get('body.descImg');
    goods.cate_id = 22;
    return goods.save();  // 開始沒有加return暑竟,所以沒捕獲到斋射,加了return就可以了
  }
}

attributes:
  • attributes:['art_id', [Sequelize.fn('COUNT','*'),'count']] // 內(nèi)置方法
  • attributes:決定返回什么字段
static async getAll(){
        const books =await HotBook.findAll({
            order:[
                'index'
            ]
        })
        const ids = []
        books.forEach((book)=>{
            ids.push(book.id)
        })
        const favors =await Favor.findAll({
            where:{
                art_id:{
                    [Op.in]:ids,
                },
                type:400
                // 國畫
                // 漫畫
            },
            group:['art_id'],
            attributes:['art_id', [Sequelize.fn('COUNT','*'),'count']]
        })
        books.forEach(book=>{
             HotBook._getEachBookStatus(book, favors)
        })
        //python 二維矩陣
        return books
    }

SQL語句:
async getUserNames (start, count) {
    const logs = await db.query(
      'SELECT lin_log.user_name AS names FROM lin_log GROUP BY lin_log.user_name HAVING COUNT(lin_log.user_name)>0 limit :count offset :start',
      {
        replacements: {
          start: start * count,
          count: count
        }
      }
    );
    const arr = Array.from(logs[0].map(it => it['names']));
    return arr;
  }

Sequelize寫入數(shù)據(jù)庫有兩種方式:

1、通過實(shí)例
save

async updateGroup (ctx, v) {
    const id = v.get('path.id');
    const exit = await ctx.manager.groupModel.findByPk(id);
    if (!exit) {
      throw new NotFound({
        msg: '分組不存在,更新失敗'
      });
    }
    exit.name = v.get('body.name');
    exit.info = v.get('body.info');
    exit.save();
  }

2罗岖、通過類方法
create increment

return sequelize.transaction(async t => {
static async like(art_id, type, uid) {
        const favor = await Favor.findOne({
            where: {
                art_id,
                type,
                uid
            }
        })
        if (favor) {
            throw new global.errs.LikeError()
        }
        return sequelize.transaction(async t => {
            await Favor.create({
                art_id,
                type,
                uid
            }, {
                transaction: t
            })
            const art = await Art.getData(art_id, type, false)
            await art.increment('fav_nums', {
                by: 1,
                transaction: t
            })
        })
    }
static async addComment(bookID, content){
        const comment = await Comment.findOne({
            where:{
                book_id:bookID,
                content
            }
        })
        if(!comment){
            // 近似
            // 你好酷 你真酷涧至,
            return await Comment.create({
                book_id: bookID,
                content,
                nums:1
            })
        }else{
            return await comment.increment('nums', {
                by: 1
            })
        }
    }

Sequelize 中文API文檔-7. Scopes 作用域的使用:

提前定義好 where 條件,然后將這種定義好的條件又可以重新組合

  • 先在define定義:
const sequelize = new Sequelize(dbName,user,password,{
    dialect:'mysql',
    host,
    port,
    logging:true,
  
    timezone: '+08:00',
    define:{
        //create_time  update_time delete_time
        timestamps:true,
        paranoid:true,
        createdAt:'created_at',
        updatedAt:'updated_at',
        deletedAt:'deleted_at',
        underscored:true,
        freezeTableName:true,
        scopes:{
            bh:{
                attributes:{
                    exclude:['updated_at','deleted_at','created_at']
                }
            }
        }
    }
})
  • 后使用:
static async _getListByType(ids, type) {
        let arts = []
        const finder = {
            where: {
                id: {
                    [Op.in]: ids
                }
            }
        }
        const scope = 'bh'
        switch (type) {
            case 100:
                arts = await Movie.scope(scope).findAll(finder)
                break
            case 200:
                arts = await Music.scope(scope).findAll(finder)
                break
            case 300:
                arts = await Sentence.scope(scope).findAll(finder)
            case 400:
                break
            default:
                break
        }
        return arts
    }

查詢范圍 Scope (預(yù)定義查詢條件)


sequelize 的op模塊:
async searchLogs (v, keyword) {
    const start = v.get('query.page');
    const count1 = v.get('query.count');
    let condition = {};
    v.get('query.name') && set(condition, 'user_name', v.get('query.name'));
    v.get('query.start') &&
      v.get('query.end') &&
      set(condition, 'time', {
        [Sequelize.Op.between]: [v.get('query.start'), v.get('query.end')]
      });
    let { rows, count } = await Log.findAndCountAll({
      where: Object.assign({}, condition, {
        message: {
          [Sequelize.Op.like]: `%${keyword}%`
        }
      }),
      offset: start * count1,
      limit: count1,
      order: [['time', 'DESC']]
    });
    return {
      rows,
      total: count
    };
  }

事務(wù)(transaction):
const { db } = require('lin-mizar/lin/db');
async createGroup (ctx, v) {
    const exit = await ctx.manager.groupModel.findOne({
      where: {
        name: v.get('body.name')
      }
    });
    if (exit) {
      throw new Forbidden({
        msg: '分組已存在,不可創(chuàng)建同名分組'
      });
    }
    let transaction;
    try {
      transaction = await db.transaction();
      const group = await ctx.manager.groupModel.create(
        {
          name: v.get('body.name'),
          info: v.get('body.info')
        },
        {
          transaction
        }
      );
      for (const item of v.get('body.auths')) {
        const { auth, module } = findMetaByAuth(item);
        await ctx.manager.authModel.create(
          {
            auth,
            module,
            group_id: group.id
          },
          {
            transaction
          }
        );
      }
      await transaction.commit();
    } catch (err) {
      if (transaction) await transaction.rollback();
    }
    return true;
  }
static async like(art_id, type, uid) {
        const favor = await Favor.findOne({
            where: {
                art_id,
                type,
                uid
            }
        })
        if (favor) {
            throw new global.errs.LikeError()
        }
        return sequelize.transaction(async t => {
            await Favor.create({
                art_id,
                type,
                uid
            }, {
                transaction: t
            })
            const art = await Art.getData(art_id, type, false)
            await art.increment('fav_nums', {
                by: 1,
                transaction: t
            })
        })
    }

    static async disLike(art_id, type, uid) {
        const favor = await Favor.findOne({
            where: {
                art_id,
                type,
                uid
            }
        })
        if (!favor) {
            throw new global.errs.DislikeError()
        }
        // Favor 表 favor 記錄
        return sequelize.transaction(async t => {
            await favor.destroy({
                force: true,
                transaction: t
            })
            const art = await Art.getData(art_id, type, false)
            await art.decrement('fav_nums', {
                by: 1,
                transaction: t
            })
        })
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捡多,一起剝皮案震驚了整個濱河市蓖康,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌垒手,老刑警劉巖蒜焊,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異科贬,居然都是意外死亡泳梆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門榜掌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來优妙,“玉大人,你說我怎么就攤上這事憎账√着穑” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵胞皱,是天一觀的道長邪意。 經(jīng)常有香客問我,道長反砌,這世上最難降的妖魔是什么雾鬼? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮宴树,結(jié)果婚禮上策菜,老公的妹妹穿的比我還像新娘。我一直安慰自己酒贬,他們只是感情好又憨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锭吨,像睡著了一般竟块。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耐齐,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼埠况。 笑死耸携,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辕翰。 我是一名探鬼主播夺衍,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沟沙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起壁榕,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牌里,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牡辽,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年麸澜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奏黑。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡炊邦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出攀涵,到底是詐尸還是另有隱情铣耘,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布以故,位于F島的核電站蜗细,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏怒详。R本人自食惡果不足惜炉媒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昆烁。 院中可真熱鬧吊骤,春花似錦、人聲如沸静尼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鸭巴,卻和暖如春眷细,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹃祖。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工溪椎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恬口。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓校读,卻偏偏與公主長得像,于是被迫代替她去往敵國和親祖能。 傳聞我的和親對象是個殘疾皇子歉秫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容