3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Objection.jsでtimestampカラム(createdAt/updatedAt)を自動更新する

Last updated at Posted at 2018-08-26

やりたいこと

Sequelizeのtimestamps機能をObjection.jsで実現する。

  • insert時に、createdAtとupdatedAtカラムに現在日時を設定する。
  • update時に、updatedAtカラムに現在日時を設定する。

前提

DBはPostgreSQL、Objection.jsはv1.2.2を使用しています。

方法1. カラムにデフォルト値を設定する

Knex.jsのマイグレーションファイルで、カラムに対してデフォルト値を設定します。

exports.up = function(knex, Promise) {
  return knex.schema.createTable('tasks', t => {
    t.increments('id').primary();
    t.string('name').notNullable();
    t.string('description').nullable();
    t.integer('assignedTo').nullable();
    t.integer('projectId').notNullable();
    t.foreign('assignedTo').references('id').inTable('users');
    t.foreign('projectId').references('id').inTable('projects');
    t.datetime('deadline').nullable();

    // デフォルト値を設定
    t.timestamp('createdAt').defaultTo(knex.fn.now());
    t.timestamp('updatedAt').defaultTo(knex.fn.now());
  });
};

exports.down = function(knex, Promise) {
  return knex.schema.dropTable('tasks');  
};

ただし、この方法だと、

insert時はSequelizeのようにcreatedAtとupdatedAtの両方が更新されますが、

update時にupdatedAtが自動更新されない問題が発生してしまいます。

  const createdTask = await Task.query()
    .insertAndFetch({
      assignedTo: 1, 
      projectId: 1,
      name: 'hoge'
    });

  // insert時は、createdAtとupdatedAtが自動で設定される。
  console.log(createdTask.createdAt != null); // true
  console.log(createdTask.updatedAt != null); // true

  const updatedTask = await Task.query()
    .patchAndFetchById(createdTask.id, {
      name: 'fuga'
    });

  console.log(updatedTask.name === 'fuga'); // true ・・・ nameは更新されている
  console.log(updatedTask.updatedAt.valueOf() === createdTask.updatedAt.valueOf()); // true ・・・ 更新されていない

方法2. hookメソッドを利用する

Objection.jsのModelクラスには、hookメソッドが定義されていて、

サブクラスでオーバーライドすることで、クエリ実行時の挙動をカスタマイズできます。

レコードのinsert前は$beforeInsert、update前は$beforeUpdateが実行されるので、

以下のように処理することで、方法1の問題を解決することができます。

  • $beforeInsertでcreatedAtとupdatedAtを更新
  • $beforeUpdateでupdatedAtを更新
const { Model } = require('objection');

class Task extends Model {
  static get tableName() { return 'tasks'; }

  $beforeInsert() {
    const now = new Date().toISOString();

    this.createdAt = now;
    this.updatedAt = now;
  }

  $beforeUpdate() {
    const now = new Date().toISOString();

    this.updatedAt = now;
  }
}

参考

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?