<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          學會Sequelize,讓你操作數(shù)據(jù)更絲滑

          共 5449字,需瀏覽 11分鐘

           ·

          2022-05-24 17:41

          Sequelize 是一個基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有強大的事務支持, 關聯(lián)關系, 預讀和延遲加載,讀取復制等功能。

          一、前言

          本文希望通過下面的知識講解及一些實戰(zhàn)經(jīng)驗分享,給予即將入門或正在學習的同學一些幫助。

          在之前剛接觸 Sequelize 的時候,遇到挺多問題,比如數(shù)據(jù)的聚合統(tǒng)計應該怎么做?復雜的排序規(guī)則應該怎么寫?索引這塊應該如何定義?性能如何衡量?等等這些問題,后來經(jīng)過自己的琢磨及與后臺人員交流探討,這些問題都得予解決。

          我們直接進入主題,學習目錄結構如下:


          • 一、前言

          • 二、入門

            • 1.配置

            • 2.創(chuàng)建模型

            • 3.增刪改查

            • 4.查詢條件

          • 三、進階

            • 1.聯(lián)表查詢

            • 2.分組

            • 3.聚合函數(shù)

            • 4 索引

            • 5.事務

          • 四、實戰(zhàn)演練

          • 五、問題思考


          二、入門

          1.配置

          module.exports?=?()?=>?{
          ?const?config?=?(exports?=?{})
          ?config.sequelize?=?{
          ??//支持的數(shù)據(jù)庫類型
          ??dialect:?'mysql',
          ??//連接數(shù)據(jù)庫的主機
          ??host:?'localhost',
          ??//連接數(shù)據(jù)庫的端口
          ??port:?3306,
          ??//數(shù)據(jù)庫名稱
          ??database:?'db_test',
          ??//數(shù)據(jù)庫用戶名
          ??username:?'root',
          ??//數(shù)據(jù)庫密碼
          ??password:?'xxxxxx',
          ??//設置標準時區(qū)
          ??timezone:?'+08:00',
          ??//配置
          ??dialectOptions:?{
          ????//?時間格式化,返回字符串
          ????dateStrings:?true,
          ????typeCast(field,?next)?{
          ??????if?(field.type?===?'DATETIME')?{
          ????????return?field.string()
          ??????}
          ??????return?next()
          ????}
          ??}
          ?}
          ?return?config
          }

          注:如果沒有加 dialectOptions 配置上的 typeCast 屬性值為 true的話,返回的時間是 ISO 標準時間日期字符。(如:'2022-04-16T15:02:08.017Z')

          2.創(chuàng)建模型

          2.1 常用數(shù)據(jù)類型

          類型說明
          INTEGER整數(shù)類型
          STRING字符串
          TEXT文本類型
          BOOLEAN布爾類型
          DATE時間類型

          像數(shù)字、字符類型默認都有一些長度的限定,有時候因為長度問題導致接口出錯,所以需要根據(jù)情況而定。

          還有其他類型就不一一列了,需要用到的可以參照文檔看看。Sequelize數(shù)據(jù)類型[1]

          2.2 定義模型

          module.exports?=?(app)?=>?{
          ??const?{?STRING,?INTEGER,?DATE?}?=?app.Sequelize

          ??const?model?=?app.model.define(
          ????'student',
          ????{
          ?????
          ??????id:?{
          ????????//類型
          ????????type:?INTEGER(11),
          ????????//是否允許為空
          ????????allowNull:?false,
          ????????//是否為主鍵
          ????????primaryKey:?true,
          ????????//自動自增
          ????????autoIncrement:?true,
          ????????//備注
          ????????comment:?'學生id',
          ??????},
          ??????name:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'學生姓名',
          ??????},
          ??????class_id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'班級',
          ??????},
          ??????cid:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????unique:?'cid',
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'身份證',
          ??????}
          ????},
          ????{
          ??????//?啟動時間,設置為ture會自動生成創(chuàng)建和更新時間,默認字段名稱為createAt、updateAt。
          ??????timestamps:?true,
          ??????//對應的表名將與model名相同
          ??????freezeTableName:?true,
          ??????//表備注
          ??????comment:?'表1',
          ??????//創(chuàng)建時間字段別名或不展示
          ??????createdAt:?'createTime',
          ??????//更新時間字段別名或不展示
          ??????updatedAt:?'updateTime'
          ????}
          ??)

          ??return?model
          }

          使用 model.sync(options) 可自動執(zhí)行 SQL 語句建表,但這個不建議用,第一這么做容易出現(xiàn)問題,第二我們的規(guī)范也不允許這么做。

          2.3 表字段規(guī)范

          這里講的是我們公司的 SQL 規(guī)范,先來看一個案例:

          CREATE?TABLE?`student`?(
          ??`id`?int?NOT?NULL?AUTO_INCREMENT?COMMENT?'學生id',
          ??`name`?varchar(50)?NOT?NULL?COMMENT?'學生姓名',
          ??`cid`?varchar(50)?NOT?NULL?COMMENT?'身份證',
          ??`class_id`?int?NOT?NULL?COMMENT?'班級',
          ??`create_time`?datetime?NOT?NULL?COMMENT?'',
          ??`update_time`?datetime?NOT?NULL?COMMENT?'更新時間',
          ??`mobile`?varchar(50)?DEFAULT?NULL?COMMENT?'手機號',
          ??PRIMARY?KEY?(`id`),
          ??UNIQUE?KEY?`cid_unique`?(`cid`),
          ??KEY?`class_id`?(`class_id`)
          )?ENGINE?=?InnoDB?DEFAULT?CHARSET?=?utf8mb4?COMMENT?=?'學生表';

          審核結果:

          審核結果

          下面講一下基本的設計規(guī)范:

          1) 禁用關鍵字

          在設計的時候注意不要用到關鍵字,比如 nametypestatus 等字段。

          常見關鍵字:

          關鍵字

          2) 字段禁止默認值為null

          從上面的案例中 mobile 字段使用了允許為 null 值,審核平臺這塊沒有強限制,但不建議用 null 為默認值,很容易出現(xiàn)問題。

          3) 需要添加字段注釋和表注釋

          CREATE?TABLE?`student`?(
          ??`id`?int?NOT?NULL?AUTO_INCREMENT?COMMENT?'學生id',
          ??`username`?varchar(50)?NOT?NULL?COMMENT?'學生姓名',
          ??`cid`?varchar(50)?NOT?NULL?COMMENT?'身份證',
          ??`class_id`?int?NOT?NULL?COMMENT?'班級',
          ??`create_time`?datetime?NOT?NULL?COMMENT?'創(chuàng)建時間',
          ??`update_time`?datetime?NOT?NULL?COMMENT?'更新時間',
          ??`mobile`?varchar(50)?DEFAULT?NULL?COMMENT?'手機號',
          ??PRIMARY?KEY?(`id`),
          ??UNIQUE?KEY?`cid`?(`cid`),
          ??KEY?`iclass_id`?(`class_id`)
          )?ENGINE?=?InnoDB?DEFAULT?CHARSET?=?utf8mb4?COMMENT?=?'學生表';

          4)創(chuàng)建時間和更新時間字段

          該表中必須含有 create_timeupdate_time 字段,如果沒有該2個字段的話審核會不通過。

          5) 索引命名

          唯一索引:必須以 uniq_ 前綴命名。

          普通索引:必須以 idx_ 前綴命名。

          索引命名

          6) 其它

          以上是常用的基本規(guī)范,更多根據(jù)自己公司情況而定。

          3.增刪改查

          3.1 create

          創(chuàng)建數(shù)據(jù)

          const?values?=?{
          ?username:?'張三',
          ?age:?18
          }
          const?result?=?await?this.model.create(values)
          console.log(result)

          3.2 findAll

          查詢數(shù)據(jù)并返回數(shù)組

          const?filter?=?{
          ?username:?'張三',
          ?age:?18
          }
          const?result?=?await?this.model.findAll({
          ?where:?filter
          })
          console.log(result)

          3.3 findAndCountAll

          查詢數(shù)據(jù)并返回總數(shù)和數(shù)組列表

          const?filter?=?{
          ?username:?'張三',
          ?age:?18
          }
          const?result?=?await?this.model.findAndCountAll({
          ?where:?filter
          })
          console.log(result)

          3.4 findOne

          查詢某一條數(shù)據(jù)返回對象

          const?filter?=?{
          ?id:?20
          }
          const?result?=?await?this.model.findOne({
          ?where:?filter
          })
          console.log(result)

          3.5 count

          返回總條數(shù)

          const?total?=?await?this.model.count()
          console.log(total)

          3.6 update

          更新數(shù)據(jù)

          const?value?=?{
          ?id:?2,
          ?username:?'張三',
          ?age:?20
          }
          const?result?=?await?this.model.update(value)
          console.log(result)

          3.7 destroy

          刪除數(shù)據(jù)

          const?filter?=?{
          ?id:?1
          }
          const?result?=?await?this.model.destroy({
          ?where:?filter
          })
          console.log(result)

          3.8 其它

          還有一些其他的方法,具體可以看看Sequelize方法文檔[2]

          4.查詢條件

          這個具體的查詢用法就不一一說了,根據(jù)自己需要的查詢條件看下對應的查詢功能即可。

          this.Op?=?this.app.Sequelize.Op
          this.model.findAll({
          ??where:?{
          ????[Op.and]:?[{?a:?5?},?{?b:?6?}],????????????//?(a?=?5)?AND?(b?=?6)
          ????[Op.or]:?[{?a:?5?},?{?b:?6?}],?????????????//?(a?=?5)?OR?(b?=?6)
          ????someAttribute:?{
          ??????//?基本
          ??????[Op.eq]:?3,??????????????????????????????//?=?3
          ??????[Op.ne]:?20,?????????????????????????????//?!=?20
          ??????[Op.is]:?null,???????????????????????????//?IS?NULL
          ??????[Op.not]:?true,??????????????????????????//?IS?NOT?TRUE
          ??????[Op.or]:?[5,?6],?????????????????????????//?(someAttribute?=?5)?OR?(someAttribute?=?6)

          ??????//?使用方言特定的列標識符?(以下示例中使用?PG):
          ??????[Op.col]:?'user.organization_id',????????//?=?"user"."organization_id"

          ??????//?數(shù)字比較
          ??????[Op.gt]:?6,??????????????????????????????//?>?6
          ??????[Op.gte]:?6,?????????????????????????????//?>=?6
          ??????[Op.lt]:?10,?????????????????????????????//?
          ??????[Op.lte]:?10,????????????????????????????//?<=?10
          ??????[Op.between]:?[6,?10],???????????????????//?BETWEEN?6?AND?10
          ??????[Op.notBetween]:?[11,?15],???????????????//?NOT?BETWEEN?11?AND?15

          ??????//?其它操作符

          ??????[Op.all]:?sequelize.literal('SELECT?1'),?//?>?ALL?(SELECT?1)

          ??????[Op.in]:?[1,?2],?????????????????????????//?IN?[1,?2]
          ??????[Op.notIn]:?[1,?2],??????????????????????//?NOT?IN?[1,?2]

          ??????[Op.like]:?'%hat',???????????????????????//?LIKE?'%hat'
          ??????[Op.notLike]:?'%hat',????????????????????//?NOT?LIKE?'%hat'
          ??????[Op.startsWith]:?'hat',??????????????????//?LIKE?'hat%'
          ??????[Op.endsWith]:?'hat',????????????????????//?LIKE?'%hat'
          ??????[Op.substring]:?'hat',???????????????????//?LIKE?'%hat%'
          ??????[Op.iLike]:?'%hat',??????????????????????//?ILIKE?'%hat'?(不區(qū)分大小寫)?(僅?PG)
          ??????[Op.notILike]:?'%hat',???????????????????//?NOT?ILIKE?'%hat'??(僅?PG)
          ??????[Op.regexp]:?'^[h|a|t]',?????????????????//?REGEXP/~?'^[h|a|t]'?(僅?MySQL/PG)
          ??????[Op.notRegexp]:?'^[h|a|t]',??????????????//?NOT?REGEXP/!~?'^[h|a|t]'?(僅?MySQL/PG)
          ??????[Op.iRegexp]:?'^[h|a|t]',????????????????//?~*?'^[h|a|t]'?(僅?PG)
          ??????[Op.notIRegexp]:?'^[h|a|t]',?????????????//?!~*?'^[h|a|t]'?(僅?PG)

          ??????[Op.any]:?[2,?3],????????????????????????//?ANY?ARRAY[2,?3]::INTEGER?(僅?PG)
          ??????[Op.match]:?Sequelize.fn('to_tsquery',?'fat?&?rat')?//?匹配文本搜索字符串?'fat'?和?'rat'?(僅?PG)

          ??????//?在?Postgres?中,?Op.like/Op.iLike/Op.notLike?可以結合?Op.any?使用:
          ??????[Op.like]:?{?[Op.any]:?['cat',?'hat']?}??//?LIKE?ANY?ARRAY['cat',?'hat']
          ????}
          ??}
          });

          三、進階

          1.聯(lián)表查詢

          1.1 一對一

          比如學生表和身份證表,一名學生只會有一個身份證號碼,一張身份證只會對應一名學生。

          這種就是一對一的關系,如圖:

          一對一

          假如學生表作為主表,身份證表作為副表,那邊這張副表的外鍵就是學生表的id。

          在使用 Sequelize 庫中,我們想通過學生表關聯(lián)到相應的身份證表信息,可通過 hasOne 方法做關聯(lián):

          student.hasOne(card,?{foreignKey?:?'id'});

          如果我們想通過身份證表反向關聯(lián)到學生表,這是可以用 belongsTo 方法做關聯(lián):

          card.belongsTo(student,?{foreignKey?:?'cid'});

          總結一下 hasOnebelongsTo 的區(qū)別:

          方法說明
          hasOne正向關聯(lián),可以理解為一名學生擁有一張身份證。
          belongsTo反向關聯(lián),可以理解為一張身份證屬于一名學生。

          1.2 一對多

          比如學生表和班級表,一名學生只有一個班級,一個班級由多名學生組成,這種是一對多(多對一)的關系,如圖:

          一對多

          在使用 Sequelize 庫中,可通過 hasMany 方法做關聯(lián):

          class.hasMany(student,?{foreignKey?:?'class_id'});

          1.3 多對多

          比如學生表和課程表,一名學生可以有多門課程,一門課程可以由多名學生參與,這種是多對多的關系,如圖:

          多對多

          在使用 Sequelize 庫中,可通過 belongsToMany 方法做關聯(lián):

          const?Student?=?sequelize.define('Student',?{?name:?DataTypes.STRING?});
          const?Course?=?sequelize.define('Course',?{?name:?DataTypes.STRING?});
          const?StudentCourse?=?sequelize.define('StudentCourse',?{
          ??studentId:?{
          ????type:?DataTypes.INTEGER,
          ????references:?{
          ??????model:?Student,
          ??????key:?'id'
          ????}
          ??},
          ??courseId:?{
          ????type:?DataTypes.INTEGER,
          ????references:?{
          ??????model:?Course,
          ??????key:?'id'
          ????}
          ??}
          });
          Student.belongsToMany(Course,?{?through:?StudentCourse?});
          Course.belongsToMany(Student,?{?through:?StudentCourse?});

          1.4 聯(lián)表查詢優(yōu)劣

          優(yōu)點:聯(lián)表查詢用起來很方便,不需要做太多了處理,尤其在 B 端場景會用的比較多。

          缺點:對于 C 端這種流量較大場景,使用聯(lián)表查詢效率會很低下,可能會導致服務器崩潰,所以現(xiàn)在大多數(shù)在 C 端都不采用 SQL 自帶的聯(lián)表查詢功能,一般會通過代碼邏輯來處理,大大減少查詢效率。

          有興趣的可以了解下 mysql 聯(lián)表查詢的步驟是怎樣的,這樣對比起來會更加直觀一點。

          2.分組

          舉個例子,你想對訂單各個狀態(tài)的數(shù)量進行一個統(tǒng)計,你應該會怎么做?

          在之前不知道分組這個功能時,我是這么做的:

          const?obj?=?{}
          obj.problemAmoumt?=?await?this.model.count()
          obj.resolvedAmoumt?=?await?this.model.count({
          ??where:?{
          ????problemStatus:2
          ??}
          })
          return?ctx.returnStatus.SUCCESS(obj)

          這似乎看起來很粗暴。

          后來發(fā)現(xiàn)可通過 SQL 語句中的 group 進行一個分組,group 是指定要進行分組的字段,示例如下:

          this.model.count({
          ?attributes:?['order_status'],
          ?group:?'order_status'
          })

          最終轉換成 SQL 語句如下:

          SELECT?`order_status`,?count(*)?AS?`count`?FROM?`order_list`?AS?`order_list`?GROUP?BY?`order_status`;

          返回結果

          [
          ?{
          ?????"order_status":?1,
          ?????"count":?4
          ?},
          ?{
          ?????"order_status":?2,
          ?????"count":?2
          ?},
          ?{
          ?????"order_status":?3,
          ?????"count":?2
          ?}
          ]

          思考:

          1.分組在應用時會不會有坑?自己在使用時可以看看。

          2.如果想對 order_status 進行一個別名 bbb 字段返回,這時的查詢語句應該如何調整?

          3.聚合函數(shù)

          3.1 count

          統(tǒng)計總數(shù),比如統(tǒng)計各個訂單的數(shù)量:

          this.model.findAll({
          ??attributes:?[
          ????'orderStatus',
          ????[sequelize.fn('count',?sequelize.col('order_status')),?'total']
          ??],
          ??group:?'orderStatus'
          })

          3.2 sum

          求和,比如統(tǒng)計全部同學的成績總數(shù):

          this.model.findAll({
          ??attributes:?[
          ????[sequelize.fn('sum',?sequelize.col('score')),?'score']
          ??]
          })

          3.3 max

          查詢最大值,比如找到這個分數(shù)最高的同學:

          this.model.findAll({
          ??attributes:?[
          ????[sequelize.fn('max',?sequelize.col('score')),?'score']
          ??]
          })

          3.4 min

          查詢最小值,比如找到這個分數(shù)最低的同學:

          this.model.findAll({
          ??attributes:?[
          ????[sequelize.fn('min',?sequelize.col('score')),?'score']
          ??]
          })

          當然這些方法也可以通過 this.model.方法(字段名稱) 來實現(xiàn),參數(shù)為指定的字段。

          4 索引

          索引就是一種將數(shù)據(jù)庫中的記錄按照特殊形式存儲的數(shù)據(jù)結構。通過索引,能夠提高數(shù)據(jù)查詢的效率,從而提升服務器的性能。

          4.1 主鍵索引

          一個表只能由一個主鍵索引,且不為空。

          可通過 primaryKey 屬性來設置主鍵,通常會把 id 設為該表的主鍵,當然你也可以指定其它字段來作為主鍵,該字段值必須是唯一的。

          ?const?student?=?app.model.define(
          ????'student',
          ????{
          ??????id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????primaryKey:?true,
          ????????autoIncrement:?true,
          ????????default:?10000,
          ????????comment:?'學生id',
          ??????},
          ??????name:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'學生姓名',
          ??????}
          ????}
          ?)
          ?return?student
          ??????

          4.2 唯一索引

          唯一索引的列的值必須唯一,但是允許出現(xiàn)空值。

          可通過 unique 屬性設置為唯一索引,值為 true 的話,索引名稱會自動生成,也可以設置為自定義索引名稱。

          ?const?student?=?app.model.define(
          ????'student',
          ????{
          ??????id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????primaryKey:?true,
          ????????autoIncrement:?true,
          ????????default:?10000,
          ????????comment:?'學生id',
          ??????},
          ??????name:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'學生姓名',
          ??????},
          ??????cid:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????unique:?'cid_unique',
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'身份證',
          ??????}
          ????}
          ?)
          ?return?student
          ??????

          4.3 組合索引

          用多個列組合構建的索引,這多個列中的值不允許有空值。

          const?student?=?app.model.define(
          ????'student',
          ????{
          ??????id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????primaryKey:?true,
          ????????autoIncrement:?true,
          ????????default:?10000,
          ????????comment:?'學生id',
          ??????},
          ??????name:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'學生姓名',
          ??????},
          ??????class_id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'班級',
          ??????},
          ??????cid:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????unique:?'cid',
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'身份證',
          ??????}
          ????},
          ????{
          ??????indexes:?[{
          ????????name:?'name',
          ????????fields:?['name']
          ??????},?{
          ????????name:?'cid',
          ????????fields:?['cid']
          ??????}]
          ????}
          ??)
          ??return?student

          4.4 普通索引

          用表中的普通列構建的索引,沒有任何限制。

          用法只要在 indexed 屬性里不設置 unique 字段即可。

          const?student?=?app.model.define(
          ????'student',
          ????{
          ??????id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????primaryKey:?true,
          ????????autoIncrement:?true,
          ????????default:?10000,
          ????????comment:?'學生id',
          ??????},
          ??????name:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'學生姓名',
          ??????},
          ??????class_id:?{
          ????????type:?INTEGER(11),
          ????????allowNull:?false,
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'班級',
          ??????},
          ??????cid:?{
          ????????type:?STRING(50),
          ????????allowNull:?false,
          ????????unique:?'cid',
          ????????validate:?{
          ??????????notEmpty:?true,
          ????????},
          ????????comment:?'身份證',
          ??????}
          ????},
          ????{
          ??????indexes:?[{
          ?????unique:?true,
          ????????name:?'name',
          ????????fields:?['name']
          ??????},?{
          ?????unique:?true,
          ????????name:?'class_id',
          ????????fields:?['class_id']
          ??????}]
          ????}
          ??)
          ??return?student

          4.5 加與不加索引的區(qū)別?

          優(yōu)點:增加索引會提供查詢效率

          缺點:增加內存空間

          我們來看一條查詢語句:

          explain?select?*?from?`experience_problem_list`?where?`experience_problem_list`.`page_type`?=?2;

          先看看沒加索引的執(zhí)行結果:

          idtypepossible_keyskeykey_lenrefrowsfilteredExtra
          1ALL(NULL)(NULL)(NULL)(NULL)1641610(NULL)

          表中總共有16416條數(shù)據(jù),掃描行數(shù)也是16416條。

          再看下加了索引的執(zhí)行結果:

          idtypepossible_keyskeykey_lenrefrowsfilteredExtra
          1refpage_typepage_type4const4100Using where

          我們來看下 rows 字段的對比,加了索引的掃描行數(shù)只有4條,由此可以看到,加索引的查詢效率大大高于普通查詢。

          5.事務

          可以理解為一個事務對應的是一組完整的業(yè)務,并且在這個事務中所作的一切操作要么全部成功,要么全部失敗,只要有一個操作沒成功,整個事務都將回滾到事務開始前。

          這里簡單放一個官方使用案例吧:

          //?首先,我們開始一個事務并將其保存到變量中
          const?t?=?await?sequelize.transaction();
          try?{
          ??//?然后,我們進行一些調用以將此事務作為參數(shù)傳遞:
          ??const?user?=?await?User.create({
          ????firstName:?'Bart',
          ????lastName:?'Simpson'
          ??},?{?transaction:?t?});
          ??await?user.addSibling({
          ????firstName:?'Lisa',
          ????lastName:?'Simpson'
          ??},?{?transaction:?t?});
          ??//?如果執(zhí)行到此行,且沒有引發(fā)任何錯誤.
          ??//?我們提交事務.
          ??await?t.commit();
          }?catch?(error)?{
          ??//?如果執(zhí)行到達此行,則拋出錯誤.
          ??//?我們回滾事務.
          ??await?t.rollback();
          }

          四、實戰(zhàn)演練

          1.查詢數(shù)據(jù)不想返回內置的數(shù)據(jù)結構,只想單純返回純數(shù)據(jù)結構怎么處理?

          來看下默認返回查詢的數(shù)據(jù)結果:

          {
          ??count:?8,
          ??rows:?[
          ????student?{
          ??????dataValues:?[Object],
          ??????_previousDataValues:?[Object],
          ??????uniqno:?1,
          ??????_changed:?Set(0)?{},
          ??????_options:?[Object],
          ??????isNewRecord:?false
          ????}
          ??]
          }

          這里 rows 里面對象返回了很多層,在業(yè)務處理時可能取值會不太方便,我們可以在調用方法的參數(shù)里加上 raw 等于 true,就返回正常的數(shù)據(jù)格式。

          const?result?=?await?this.model.findAll({
          ?where:?filter,
          ?raw:?true
          })

          返回:

          {
          ??count:?8,
          ??rows:?[
          ????{
          ??????id:?8,
          ??????name:?'張三',
          ??????cid:?'xxx',
          ??????createTime:?'2022-04-08?18:06:52',
          ??????updateTime:?'2022-04-08?18:06:52'
          ????}
          ??]
          }

          2.如果列表篩選涉及到主副表應該怎么查詢合適?

          有幾種方案:

          1)直接用 mysql 語句做表關聯(lián)即可,但性能比較低下。

          2)用代碼邏輯處理,但寫起來可能有點繞,但效率比直接用 mysql 表關聯(lián)效率高。

          3)如果主表字段固定且不多的話,可以直接冗余副表中,但如果后續(xù)主表加字段的話,副表更新是個問題。

          4)采用 ES,將這2張表的數(shù)據(jù)合并同步到 ES 的一張表里,但 ES 使用場景一般都是量很大的,加上 nodejs 新增其它數(shù)據(jù)庫交互,有額外的開銷成本。

          綜合以上考慮,如果是內部項目,量也不是很多的話,查詢比較復雜的話可以直接采用第一種方法,如果邏輯相對比較簡單,也可以采用第二種方法。

          3.分組 group 遇到的問題。

          group 只能填寫已有的查詢字段。比如你表中有這個字段 aaa,但查詢返回的字段 aaa 被過濾了,這時不能以 aaa 進行分組。

          4.如何獲取今日、最近7天、一個月的數(shù)據(jù)?

          可通過字符串函數(shù) DATE_FORMAT 實現(xiàn):

          1)首先通過時間選擇器獲取到今日、最近7天、一個月的開始時間和結束時間。

          2)然后使用對改模型使用 count 進行查詢,這時獲取到的知識該時期的總條數(shù)。

          3)對改數(shù)據(jù)進行分組,使用 group 屬性,字段為創(chuàng)建的時間,但我們創(chuàng)建的時間是包含時分秒的,如果這么聚合的話,生成的數(shù)據(jù)并不是我們想到的,我們需要的是針對年月日,所以需要對這個時間進行一個處理。

          [
          ????{
          ????????"create_time":?"2022-04-12?17:02:36",
          ????????"count":?1
          ????},
          ????{
          ????????"create_time":?"2022-04-14?17:02:38",
          ????????"count":?1
          ????},
          ????{
          ????????"create_time":?"2022-04-14?17:03:38",
          ????????"count":?1
          ????},
          ????{
          ????????"create_time":?"2022-04-14?17:03:58",
          ????????"count":?1
          ????}
          ]

          這個顯然不是我們想要的一個結果。

          4)然后函數(shù) DATE_FORMAT,將時間格式化為年月日。

          總體實現(xiàn)如下:

          const?countArr?=?await?this.model.count({
          ??where:?filter,
          ??attributes:?[
          ????[sequelize.fn('DATE_FORMAT',?sequelize.col('create_time'),?'%Y-%m-%d'),?'createTime'],
          ??],?group:?'createTime',
          })

          假設我想獲取4月10日-4月14日的數(shù)據(jù),正常返回結構如下:

          [
          ????{
          ????????"createTime":?"2022-04-12",
          ????????"count":?1
          ????},
          ????{
          ????????"createTime":?"2022-04-14",
          ????????"count":?3
          ????}
          ]

          5)因為表中只有12號和14號的數(shù)據(jù),10、11、13號沒有,這塊需要自己對代碼進行一個處理,把其它日期沒有的數(shù)據(jù)為0即可。

          最終希望達到的效果:

          [
          ?{
          ?????"time":?"2022-04-10",
          ?????"count":?0
          ?},
          ?{
          ?????"time":?"2022-04-11",
          ?????"count":?0
          ?},
          ?{
          ?????"time":?"2022-04-12",
          ?????"count":?1
          ?},
          ?{
          ?????"time":?"2022-04-13",
          ?????"count":?0
          ?},
          ?{
          ?????"time":?"2022-04-14",
          ?????"count":?3
          ?}
          ]

          五、問題思考

          1. 如果想要獲取一年中每個月的訂單量,應該怎么查詢?

          答案:關注 ?"大轉轉FE" 公眾號,回復"統(tǒng)計"、"一年"其中一個即可

          1. 如何根據(jù)查詢條件的順序,返回相應的數(shù)據(jù)順序?

          答案:關注 ?"大轉轉FE" 公眾號,,回復"filed"、"排序"其中一個即可

          1. 如何進行動態(tài)分表?

          答案:關注 ?"大轉轉FE" 公眾號,回復"分表"即可。

          注:如果您還有其它問題想交流,歡迎在底部留言。

          參考資料

          [1]

          Sequelize數(shù)據(jù)類型: https://www.sequelize.com.cn/core-concepts/model-basics

          [2]

          Sequelize方法文檔: https://www.sequelize.com.cn/core-concepts/model-querying-finders


          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级黄色视频国产 | 欧美激情一级免费片在线观看 | 国产精品视频免费看 | 大香蕉伊人免费在线视频 | 欧美色图色就是色 |