web-dev-qa-db-ja.com

Knex.JS自動更新トリガー

Knex.JS 移行ツールを使用しています。ただし、テーブルを作成するときに、データベースでレコードが更新されると自動的に更新されるupdated_atという名前の列が必要です。

たとえば、ここにテーブルがあります:

knex.schema.createTable('table_name', function(table) {
    table.increments();
    table.string('name');
    table.timestamp("created_at").defaultTo(knex.fn.now());
    table.timestamp("updated_at").defaultTo(knex.fn.now());
    table.timestamp("deleted_at");
})

created_at列とupdated_at列のデフォルトは、レコードが作成された時刻ですが、これで問題ありません。しかし、そのレコードが更新されたときに、updated_at列に、自動的に更新された新しい時刻を表示したいと考えています。

私は生のpostgresで書いたくない。

ありがとう!

20
aashah7

ベニーの答えは完全に正しいです。しかし、私はあなたがPostgresに具体的に言及していることに気づきます。その場合、彼のknex.raw構文はあなたのために機能しません。これが私がうまく使った方法です。

関数を追加する

設定された順序で複数の移行ファイルがある場合、ファイル名の日付スタンプを人為的に変更して、これを最初に実行する(または最初の移行ファイルに追加する)必要がある場合があります。ロールバックできない場合は、psqlを使用してこの手順を手動で実行する必要があります。ただし、新しいプロジェクトの場合:

const ON_UPDATE_TIMESTAMP_FUNCTION = `
  CREATE OR REPLACE FUNCTION on_update_timestamp()
  RETURNS trigger AS $$
  BEGIN
    NEW.updated_at = now();
    RETURN NEW;
  END;
$$ language 'plpgsql';
`

const DROP_ON_UPDATE_TIMESTAMP_FUNCTION = `DROP FUNCTION on_update_timestamp`

exports.up = knex => knex.raw(ON_UPDATE_TIMESTAMP_FUNCTION)
exports.down = knex => knex.raw(DROP_ON_UPDATE_TIMESTAMP_FUNCTION)

これで、関数は後続のすべての移行で使用できるようになります。

knex.rawトリガーヘルパーを定義する

回避できる場合は、移行ファイルでSQLの大きなチャンクを繰り返さないほうが表現力があると思います。ここではknexfile.jsを使用しましたが、複雑にしたくない場合は、どこにでも定義できます。

module.exports = {
  development: {
    // ...
  },

  production: {
    // ...
  },

  onUpdateTrigger: table => `
    CREATE TRIGGER ${table}_updated_at
    BEFORE UPDATE ON ${table}
    FOR EACH ROW
    EXECUTE PROCEDURE on_update_timestamp();
  `
}

ヘルパーを使用する

最後に、自動更新トリガーをかなり便利に定義できます。

const { onUpdateTrigger } = require('../knexfile')

exports.up = knex =>
  knex.schema.createTable('posts', t => {
    t.increments()
    t.string('title')
    t.string('body')
    t.timestamps(true, true)
  })
    .then(() => knex.raw(onUpdateTrigger('posts')))

exports.down = knex => knex.schema.dropTable('posts')

テーブルを削除するだけでトリガーを取り除くことができます。明示的なDROP TRIGGERは必要ありません。

これはすべて大変な作業のように思えるかもしれませんが、一度実行すればかなり簡単に設定でき、ORMの使用を避けたい場合には便利です。

20
Rich Churcher

timestamps を使用してknexマイグレーションを作成できます:

exports.up = (knex, Promise) => {
  return Promise.all([
    knex.schema.createTable('table_name', (table) => {
      table.increments();
      table.string('name');
      table.timestamps(false, true);
      table.timestamp('deleted_at').defaultTo(knex.fn.now());
    })
  ]);
};

exports.down = (knex, Promise) => {
  return Promise.all([
    knex.schema.dropTableIfExists('table_name')
  ]);
};

timestamps の場合、created_at列とupdated_at列を追加するデータベーススキーマが作成され、それぞれに初期タイムスタンプが含まれます。

updated_at列を最新に保つには、knex.rawが必要です。

table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

knex.rawソリューションをスキップするには、 Objection.js のような高レベルのORMを使用することをお勧めします。 Objection.js を使用すると、独自のBaseModelを実装して、updated_at列を更新できます。

Something.js

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

class Something extends BaseModel {
  constructor() {
    super();
  }

  static get tableName() {
    return 'table_name';
  }
}

module.exports = Something;

BaseModel

const knexfile = require('../../knexfile');
const knex = require('knex')(knexfile.development);
const Model = require('objection').Model;

class BaseModel extends Model {
  $beforeUpdate() {
    this.updated_at = knex.fn.now();
  }
}

module.exports = BaseModel;

ソース: http://vincit.github.io/objection.js/#timestamps

7

これはKnexの機能ではありません。 Knexは列を作成するだけで、最新の状態に保ちません。

ただし、Bookshelf ORMを使用する場合は、テーブルにタイムスタンプがあることを指定でき、期待どおりに列を設定および更新します。

0
Swaraj

これはMysql 5.6+でそれを行う私の方法です

Table.timestampsを使用しなかった理由は、タイムスタンプではなくDATETIMEを使用しているためです。

table.dateTime('created_on')
        .notNullable()
        .defaultTo(knex.raw('CURRENT_TIMESTAMP'))

table.dateTime('updated_on')
        .notNullable()
        .defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
0
Alex Rizvi