[ 筆記 ] Express 03 - ORM & Sequelize


Posted by krebikshaw on 2020-10-10

初探 ORM

物件關聯對映(英語:Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式設計技術,用於實現物件導向程式語言裡不同類型系統的資料之間的轉換。 從效果上說,它其實是建立了一個可在程式語言裡使用的「虛擬物件資料庫」。

簡單講就是,透過 ORM 可以幫我們把程式語言的「物件」跟資料庫的資料做一個對應關係,可以透過操縱物件,來改動資料庫的資料。

Sequelize

安裝:

$ npm install --save sequelize

依照我們所使用的資料庫,安裝對應的工具(這邊以 mysql2 做示範)

# One of the following:
$ npm install --save pg pg-hstore # Postgres
$ npm install --save mysql2
$ npm install --save mariadb
$ npm install --save sqlite3
$ npm install --save tedious # Microsoft SQL Server

使用方式:

先在 mysql 中建立好一個需要連線的資料庫,接著在 Express 中做下列設定

const Sequelize = require('sequelize');   // 引入 sequelize

// 填入對應的資料庫帳號
const sequelize = new Sequelize('database', 'username', 'password',  {
  host: 'localhost',
  dialect: 'mysql'
});

上面這些設定完成之後,就可以跟資料庫建立連線了,接下來要做欄位的設定

欄位設定:

由於 ORM 是利用物件跟資料庫做連線,所以資料庫欄位中的設定(資料型態,是否可以為空....),也是寫在物件中的

const User = sequelize.define('user', {
  // attributes
  firstName: {
    type: Sequelize.STRING,   //  資料型態
    allowNull: false          //  是否可以為空
  },
  lastName: {
    type: Sequelize.STRING
    // allowNull defaults to true
  }
}, {
  // options
});

這裡為基本的型態設定,詳細設定方式,可以參考 官方文件

上面這些欄位設定好了之後,需要利用 sequelize.sync() 來讓 Sequelize 幫你去資料庫把欄位建立起來,這個指令會回傳一個 promise,所以要用 .then() 來接續後面的動作。

// Note: using `force: true` will drop the table if it already exists
sequelize.sync({ force: true }).then()

如果要新增資料的話,在 .then() 裡面用 <Table Name>.create(),在裡面填上欄位名稱跟資料內容

sequelize.sync({ force: true }).then(() => {
  // Now the `users` table in the database corresponds to the model definition
  return User.create({
    firstName: 'John',
    lastName: 'Hancock'
  });
});

如果要 select 所有資料,在 .then() 裡面用 <Table Name>.findAll(),由於 findAll() 會回傳 promise,所以也要用 .then() 來接

sequelize.sync({ force: true }).then(() => {
  User.findAll().then(users => {
    console.log("All users:", JSON.stringify(users, null, 4));
  });
}

如果要設定 select 的 where 條件,可以這樣寫:

sequelize.sync({ force: true }).then(() => {
  User.findAll({         //  條件寫在 () 括號裡面用 {} 大括號包住
    where: {            //  where 裡面的內容也是用物件包住
      firstName: 'John'
    }
  }).then(users => {
    console.log("All users:", JSON.stringify(users, null, 4));
  });
}

上面這個寫法相當於 select * from User where firstName = John

  • 如果想透過 id 來撈取資料,可以使用 findOne(),再將 id 寫在 where 條件裡
sequelize.sync({ force: true }).then(() => {
  User.findOne({
    where: {
      id: '1'
    }
  }).then(user => {
    console.log(user.firstName);
  });
}
  • 撈取到指定資料之後,假如我們要將資料做更新,我們可以用 .then(),並且在裡頭的 function 回傳一個 user.update()
sequelize.sync({ force: true }).then(() => {
  User.findOne({
    where: {
      id: '1'
    }
  }).then(user => {
    user.update({          //  將要更新的資料內容寫在 () 括號裡面用 {} 大括號包住
      lastName: 'hahaha'
    })
  }).then(() => {
    console.log('update done');
  })
}
  • 要將資料做刪除,我們可以用 .then(),並且在裡頭的 function 回傳一個 user.destroy()
sequelize.sync({ force: true }).then(() => {
  User.findOne({
    where: {
      id: '1'
    }
  }).then(user => {
    user.destroy().then(() => {
      console.log('destroy done');
    })
  })
}

Associations 資料庫關聯

關聯式資料庫,可以將兩個不同的 table 做關聯(ex. user.id 對應到 comment.userId)

當我們要利用 ORM 將兩個 table 做關聯的時候,需要用到一個指令:User.hasMany(Comment)
告訴 Sequelize 一個 user 會對應到好幾個 comment,這樣它就會利用 User.id 幫我們建立起關聯

const User = sequelize.define('user', {
  // attributes
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
  }
});

const Comment = sequelize.define('comment', {
  content: {
    type: Sequelize.STRING
  }
});

User.hasMany(Comment);   將兩個 table 做關聯
Comment.belongsTo(User);

當我們要在 comment 填入資料的時候,要記得也把 userId 一起新增進去

sequelize.sync().then(() => {
  Comment.create({
    userId: 2,
    content: 'I am 2'
  }).then(() => {
    console.log('create done');
  });
});

當我們在撈取資料的時候,就可以利用關聯的 id 來撈取 comment
下面程式碼示範:找出一個使用者叫做 John 並把他有發過的所有 comment 都撈出來

sequelize.sync().then(() => {
  User.findOne({
    where: {
      firstName: 'John'
    },
    include: [comment]     //  用一個陣列把要撈取的 table 一起放進來
  }).then(user => {
    console.log(JSON.stringify(user.comments, null, 4))   // 篩選我們要的資料
  })
})

Sequelize CLI

為了讓實際開發時,程式碼更有結構,可以安裝 Sequelize CLI 這套工具,可以參考 官方文件 Migrations

安裝:
$ npm install --save sequelize-cli
$ npx sequelize-cli init

上面 init 會幫我們做好一些初始化設定,等它跑完之後,可以打開 config.json 這個檔案,裡面可以更改我們連到資料庫的設定(帳號密碼)。

使用方式:

建立 Model

$ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
$ npx sequelize-cli model:generate --name Comment --attributes content:string

建立好 Model 之後,可以在 Model 這個資料夾底下看到 Sequelize 幫你建立的檔案,這些檔案中的設定可以讓我們幾去做微調

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Comment = sequelize.define('Comment', {
    content: DataTypes.STRING
  }, {});
  Comment.associate = function(models) {
    //  這邊要自行加上關聯的設定
    Comment.belongsTo(Models.User);
  };
  return Comment;
}

設定完這些檔案之後,資料庫裡面目前還不會有任何東西。

我們要透過 Migrations,依照我們在 Model 做的設定去實際去改動資料庫的內容

$ npx sequelize-cli db:migrate

接著到 migrations 這個資料夾底下,找到 Comment 的檔案去新增 UserId 這個關聯用的欄位,存擋之後。讓 Migrations 重跑一遍,把 UserId 加進資料庫當中

$ npx sequelize-cli db:migrate:undo
$ npx sequelize-cli db:migrate

這段指令跑完之後,資料庫就可以看到 User Comment 兩個 table
由於 Models 資料夾底下的 index.js 都幫我們把我們需要用到的內容打包成一個 db exports 出去了,所以在外頭利用 require 把 Models 底下的 index.js 引入,就可以來操縱這些資料。

操縱資料

回到 Models 資料夾外面,我們可以在 index.js 引入 Models 裡面的東西

const db = require('./models');

我們就可以透過 index.js 來操控資料:

const db = require('./models');
const User = db.User;
const Comment = db.Comment;

User.create({
  firstName: 'John'
}).then(() => {
  console.log('create done');
});

#Sequelize







Related Posts

七天打造自己的 Google Map 應用入門 - Day07

七天打造自己的 Google Map 應用入門 - Day07

跨領域自學程式設計常見問題解析 FAQ

跨領域自學程式設計常見問題解析 FAQ

React Form: Redux Form vs React Final Form vs Formik and Yup

React Form: Redux Form vs React Final Form vs Formik and Yup


Comments