読者です 読者をやめる 読者になる 読者になる

あいつの日誌β

あいつの日誌です。

sequelize tutorial belongTo

sequelize で belongTo をするやり方を思い出しやすいようにメモに残します。

準備

mkdir practice-sequelize && cd $_
npm init --yes
cat << EOS > .gitignore
node_modules
npm-debug.log*
db
EOS
mkdir db
npm install sqlite sequelize --save
npm install sequelize-cli --save-dev
git init && git add . && git commit -m 'first commit'

雛形を生成する

$(npm bin)/sequelize init
cat << EOS > config/config.json
{
  "development": {
    "dialect": "sqlite",
    "storage": "./db/development.db"
  },  
  "test": {
    "dialect": "sqlite",
    "storage": "./db/test.db"
  },  
  "production": {
    "dialect": "sqlite",
    "storage": "./db/production.db"
  }
}
EOS
git add config models && git commit -m 'db initialize'

モデルを作成する

$(npm bin)/sequelize model:create --name Todo --attributes "title:string, complete:boolean"
$(npm bin)/sequelize model:create --name User --attributes "email:string"
sed -i '' -e 's/\/\/ associations can be defined here/Todo.belongsTo(models.User);/' models/todo.js
git add models migrations && git commit -m 'add new models'

マイグレーションを実行

$(npm bin)/sequelize db:migrate 

テーブルが作成されている事を確認する

% sqlite3 db/development.db '.schema'
CREATE TABLE `SequelizeMeta` (`name` VARCHAR(255) NOT NULL UNIQUE PRIMARY KEY, UNIQUE (name));
CREATE TABLE `Todos` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` VARCHAR(255), `complete` TINYINT(1), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
CREATE TABLE `Users` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `email` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);

Fixture を作る

本来は seeders がそれに相当すると思いますがちょっと使いづらいので無視して自前で作成します。

create test/fixture/{user.js,todo.js,index.js}

mkdir -p test/fixture
cat << EOS > test/fixture/user.js
'use strict';

module.exports = (models) => {
  return models.User.bulkCreate([
    {   
      id: 1,
      email: 'admin@exmaple.com',
    },  
    {   
      id: 2,
      email: 'info@example.com',
    },  
  ])  
}
EOS
cat << EOS > test/fixture/todo.js
'use strict';

module.exports = (models) => {
  return models.Todo.bulkCreate([
    {   
      id: 1,
      title: 'todo:1',
      complete: true,
      UserId: 1
    },  
    {   
      id: 2,
      title: 'todo:2',
      complete: true,
      UserId: 1
    },  
    {   
      id: 3,
      title: 'todo:3',
      complete: false,
      UserId: 2
    }   
  ])  
}
EOS
cat << EOS > test/fixture/index.js
'use strict';

module.exports = (models) => {
  const Promise = models.Sequelize.Promise;

  return Promise.all([
    require('./user')(models),
    require('./todo')(models)
  ])  
}
EOS

create bin/sync:

cat << EOS > bin/sync
#!/usr/bin/env node

'use strict';

const models = require('../models');
const fixture = require('../test/fixture');

models.sequelize.sync({
  force: true,
  logging: console.log,
})
.then(() => {
  return fixture(models);
})
.then(() => {
  return models.sequelize.close();
})
EOS

実行

chmod +x bin/sync
bin/sync

使ってみる

mkdir example
touch example/todo_list.js

edit example/todo_list.js

cat << EOS > example/todo_list.js
'use strict';

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

models.Todo.findAll({
  include: [models.User]
}).then((todos) => {
  todos.forEach((todo) => {
    console.log(JSON.stringify(todo));
    console.log(JSON.stringify(todo.User));
  }); 
});
EOS

result

:!node example/todo_list.js
Executing (default): SELECT `Todo`.`id`, `Todo`.`title`, `Todo`.`complete`, `Todo`.`createdAt`, `Todo`.`updatedAt`, `Todo`.`UserId`, `User`.`id` AS `User.id`, `User`.`email` AS `User.email`, `User`.`createdAt` AS `User.createdAt`, `User`.`updatedAt` AS `User.updatedAt` FROM `Todos` AS `Todo` LEFT OUTER JOIN `Users` AS `User` ON `Todo`.`UserId` = `User`.`id`;
{"id":1,"title":"todo:1","complete":true,"createdAt":"2016-03-24T09:22:51.740Z","updatedAt":"2016-03-24T09:22:51.740Z","UserId":1,"User":{"id":1,"email":"admin@exmaple.com","createdAt":"2016-03-24T09:22:51.738Z","updatedAt":"2016-03-24T09:22:51.738Z"}}
{"id":1,"email":"admin@exmaple.com","createdAt":"2016-03-24T09:22:51.738Z","updatedAt":"2016-03-24T09:22:51.738Z"}
{"id":2,"title":"todo:2","complete":true,"createdAt":"2016-03-24T09:22:51.740Z","updatedAt":"2016-03-24T09:22:51.740Z","UserId":1,"User":{"id":1,"email":"admin@exmaple.com","createdAt":"2016-03-24T09:22:51.738Z","updatedAt":"2016-03-24T09:22:51.738Z"}}
{"id":1,"email":"admin@exmaple.com","createdAt":"2016-03-24T09:22:51.738Z","updatedAt":"2016-03-24T09:22:51.738Z"}
{"id":3,"title":"todo:3","complete":false,"createdAt":"2016-03-24T09:22:51.740Z","updatedAt":"2016-03-24T09:22:51.740Z","UserId":2,"User":{"id":2,"email":"info@example.com","createdAt":"2016-03-24T09:22:51.738Z","updatedAt":"2016-03-24T09:22:51.738Z"}}
{"id":2,"email":"info@example.com","createdAt":"2016-03-24T09:22:51.738Z","updatedAt":"2016-03-24T09:22:51.738Z"}

SEE ALSO

http://qiita.com/loremipsumjp/items/389516ab022b5222a787