SequelizeでAssociationを設定する

ローカルでのアプリ作成

プロジェクト作成

npm init -y

package.jsonのscriptsの中に下記の行を追加してください。

"start": "node index.js",

必要なライブラリをインストール

npm i mysql2 dotenv sequelize --save
npm i sequelize-cli -D

.

MySQLの設定

mysqlにログインし、データベースを作成しましょう。

mysql -u root -p
create database dev;

ここでユーザー名、パスワード、デーベース名を控えておきましょう。



sequelizeの設定

プロジェクトルートに「.sequelizerc」ファイルを作成し、
下記のように記述してください

// .sequelizerc

const path = require('path');

module.exports = {
  'config': path.resolve('db/config', 'config.js'),
  'models-path': path.resolve('db', 'models'),
  'seeders-path': path.resolve('db', 'seeders'),
  'migrations-path': path.resolve('db', 'migrations')
};

その後下記コマンドを実行してください。

npx sequelize-cli init

生成されたフォルダを確認しましょう。
f:id:noifuji:20210402151010p:plain

「db/config/config.js」を下記のように修正してください。

require('dotenv').config();

module.exports = {
    "development": {
        "username": process.env.RDS_USERNAME,
        "password": process.env.RDS_PASSWORD,
        "database": process.env.RDS_DB_NAME,
        "host": process.env.RDS_HOSTNAME,
        "dialect": "mysql"
    },
    "test": {
        "username": "root",
        "password": null,
        "database": "database_test",
        "host": "127.0.0.1",
        "dialect": "mysql"
    },
    "production": {
        "username": "root",
        "password": null,
        "database": "database_production",
        "host": "127.0.0.1",
        "dialect": "mysql"
    }
};

.


環境変数の設定

プロジェクトルートに「.env」を作成しましょう。

RDS_HOSTNAME=<ここにデータベースのホスト名(ローカルならlocalhost)>
RDS_USERNAME=<ここにデータベースのユーザー名>
RDS_PASSWORD=<ここにデータベースのパスワード>
RDS_DB_NAME=<ここにデータベース名>

.


テーブルの構築

sequelizeでUsersとFriendsモデルを作成します。

npx sequelize-cli model:generate --name Users --attributes firstName:string,lastName:string,email:string
npx sequelize-cli model:generate --name Friends --attributes userId:integer,friendName:string,lineId:string

FriendsのuserIdに外部キー制約を設定するため、
ファイル「db/migrations/************-create-friends.js」のuserIdの要素を下記のように修正してください。

/****省略****/

userId: {
        type: Sequelize.INTEGER,
        onDelete: 'CASCADE',
        references: {
          model: 'Users',
          key: 'id',
          as: 'userId',
        }
      },

/****省略****/

UsersとFriendsの関係を表現するため、モデルファイルを下記のように修正してください。
【db/models/users.js】

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Users 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
    }
  };
  Users.init({
    firstName: DataTypes.STRING,
    lastName: DataTypes.STRING,
    email: DataTypes.STRING
  }, {
    sequelize,
    modelName: 'Users',
  });
  
  Users.associate = function(models) {
    // associations can be defined here
    Users.hasMany(models.Friends, {
      foreignKey: 'userId',
    });
  };
  
  return Users;
};

【db/models/friends.js】

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Friends 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
    }
  };
  Friends.init({
    userId: DataTypes.INTEGER,
    friendName: DataTypes.STRING,
    lineId: DataTypes.STRING
  }, {
    sequelize,
    modelName: 'Friends',
  });

  Friends.associate = function(models) {
    // associations can be defined here
    Friends.belongsTo(models.Users, {
      foreignKey: 'userId',
      onDelete: 'CASCADE'
    })
  };

  return Friends;
};


マイグレーションを行います。

npx sequelize-cli db:migrate

次に初期データの投入を行うため、seedを作成します。

npx sequelize-cli seed:generate --name demo-user
npx sequelize-cli seed:generate --name demo-friend

「db/seeders」フォルダに新たにファイルが生成されるので、次のように修正してください。
【******-demo-user.js】

'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    /**
     * Add seed commands here.
     *
     * Example:
     * await queryInterface.bulkInsert('People', [{
     *   name: 'John Doe',
     *   isBetaMember: false
     * }], {});
    */
    
    return queryInterface.bulkInsert('Users', [{
      firstName: 'Mike',
      lastName: 'Doe',
      email: 'example@example.com',
      createdAt: new Date(),
      updatedAt: new Date()
    },
    {
      firstName: 'Mike2',
      lastName: 'Doe2',
      email: 'example2@example.com',
      createdAt: new Date(),
      updatedAt: new Date()
    }]);
  },

  down: async (queryInterface, Sequelize) => {
    /**
     * Add commands to revert seed here.
     *
     * Example:
     * await queryInterface.bulkDelete('People', null, {});
     */
  }
};

【******-demo-friend.js】

'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    /**
     * Add seed commands here.
     *
     * Example:
     * await queryInterface.bulkInsert('People', [{
     *   name: 'John Doe',
     *   isBetaMember: false
     * }], {});
    */
    return queryInterface.bulkInsert('Friends', [{
      userId: '1',
      friendName: 'aaaaa',
      lineId: 'fwdgwhgreheg',
      createdAt: new Date(),
      updatedAt: new Date()
    },
    {
      userId: '1',
      friendName: 'afffffaaaa',
      lineId: 'fwdgwhgssssssssssreheg',
      createdAt: new Date(),
      updatedAt: new Date()
    }]);
  },

  down: async (queryInterface, Sequelize) => {
    /**
     * Add commands to revert seed here.
     *
     * Example:
     * await queryInterface.bulkDelete('People', null, {});
     */
  }
};

次に、実際にテーブルへデータ投入します。

npx sequelize-cli db:seed:all

.


index.jsの作成

プロジェクトルートにindex.jsを作成しましょう。

require('dotenv').config();
const db = require('./db/models/index');

(async function() {

const users = await db.Users.findAll({ include: db.Friends });
console.log(users.every(user => user instanceof db.Users));
console.log("All users:", JSON.stringify(users, null, 2));

})();

ここまで作成できたら、下記のコマンドでアプリを実行してください。

npm start

このように表示されたら成功です。

> tmp@1.0.0 start /home/ubuntu/environment/tmp
> node index.js

Executing (default): SELECT `Users`.`id`, `Users`.`firstName`, `Users`.`lastName`, `Users`.`email`, `Users`.`createdAt`, `Users`.`updatedAt`, `Friends`.`id` AS `Friends.id`, `Friends`.`userId` AS `Friends.userId`, `Friends`.`friendName` AS `Friends.friendName`, `Friends`.`lineId` AS `Friends.lineId`, `Friends`.`createdAt` AS `Friends.createdAt`, `Friends`.`updatedAt` AS `Friends.updatedAt` FROM `Users` AS `Users` LEFT OUTER JOIN `Friends` AS `Friends` ON `Users`.`id` = `Friends`.`userId`;
true
All users: [
  {
    "id": 1,
    "firstName": "Mike",
    "lastName": "Doe",
    "email": "example@example.com",
    "createdAt": "2021-04-14T12:59:22.000Z",
    "updatedAt": "2021-04-14T12:59:22.000Z",
    "Friends": [
      {
        "id": 1,
        "userId": 1,
        "friendName": "aaaaa",
        "lineId": "fwdgwhgreheg",
        "createdAt": "2021-04-14T12:59:22.000Z",
        "updatedAt": "2021-04-14T12:59:22.000Z"
      },
      {
        "id": 2,
        "userId": 1,
        "friendName": "afffffaaaa",
        "lineId": "fwdgwhgssssssssssreheg",
        "createdAt": "2021-04-14T12:59:22.000Z",
        "updatedAt": "2021-04-14T12:59:22.000Z"
      }
    ]
  },
  {
    "id": 2,
    "firstName": "Mike2",
    "lastName": "Doe2",
    "email": "example2@example.com",
    "createdAt": "2021-04-14T12:59:22.000Z",
    "updatedAt": "2021-04-14T12:59:22.000Z",
    "Friends": []
  }
]