命名戦略
underscoredオプション
Sequelizeはモデルにunderscoredオプションを提供します。trueの場合、このオプションはすべての属性のfieldオプションを、その名前のスネークケースバージョンに設定します。これは、アソシエーションによって自動的に生成される外部キーやその他の自動的に生成されるフィールドにも適用されます。例
const User = sequelize.define(
  'user',
  { username: Sequelize.STRING },
  {
    underscored: true,
  },
);
const Task = sequelize.define(
  'task',
  { title: Sequelize.STRING },
  {
    underscored: true,
  },
);
User.hasMany(Task);
Task.belongsTo(User);
上記では、UserモデルとTaskモデルの両方がunderscoredオプションを使用しています。また、それらの間に一対多のリレーションシップがあります。また、timestampsはデフォルトでtrueであるため、createdAtおよびupdatedAtフィールドも自動的に作成されるはずです。
underscoredオプションがない場合、Sequelizeは自動的に次のように定義します。
- 各モデルのcreatedAt属性。各テーブルのcreatedAtという名前の列を指します。
- 各モデルのupdatedAt属性。各テーブルのupdatedAtという名前の列を指します。
- Taskモデルの- userId属性。taskテーブルの- userIdという名前の列を指します。
underscoredオプションが有効になっている場合、Sequelizeは代わりに次のように定義します。
- 各モデルのcreatedAt属性。各テーブルのcreated_atという名前の列を指します。
- 各モデルのupdatedAt属性。各テーブルのupdated_atという名前の列を指します。
- Taskモデルの- userId属性。taskテーブルの- user_idという名前の列を指します。
どちらの場合も、フィールドはJavaScript側ではキャメルケースであることに注意してください。このオプションは、これらのフィールドがデータベース自体にどのようにマッピングされるかのみを変更します。すべての属性のfieldオプションは、スネークケースバージョンに設定されますが、属性自体はキャメルケースのままです。
このように、上記のコードでsync()を呼び出すと、次のものが生成されます。
CREATE TABLE IF NOT EXISTS "users" (
  "id" SERIAL,
  "username" VARCHAR(255),
  "created_at" TIMESTAMP WITH TIME ZONE NOT NULL,
  "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL,
  PRIMARY KEY ("id")
);
CREATE TABLE IF NOT EXISTS "tasks" (
  "id" SERIAL,
  "title" VARCHAR(255),
  "created_at" TIMESTAMP WITH TIME ZONE NOT NULL,
  "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL,
  "user_id" INTEGER REFERENCES "users" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
  PRIMARY KEY ("id")
);
単数形と複数形
一見すると、Sequelizeで名前の単数形と複数形のどちらを使用する必要があるかについて混乱する可能性があります。このセクションでは、それを少し明確にすることを目的としています。
Sequelizeは、内部でinflectionというライブラリを使用しているため、不規則な複数形(person -> peopleなど)が正しく計算されることに注意してください。ただし、別の言語で作業している場合は、名前の単数形と複数形を直接定義することもできます。sequelizeを使用すると、いくつかのオプションを使用してこれを行うことができます。
モデルを定義する場合
モデルは単数形で定義する必要があります。例
sequelize.define('foo', { name: DataTypes.STRING });
上記では、モデル名はfoo(単数形)であり、それぞれのテーブル名はfoosです。Sequelizeはテーブル名の複数形を自動的に取得するためです。
モデルで参照キーを定義する場合
sequelize.define('foo', {
  name: DataTypes.STRING,
  barId: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: 'bars',
      key: 'id',
    },
    onDelete: 'CASCADE',
  },
});
上記の例では、別のモデルを参照するキーを手動で定義しています。これを行うことは通常ではありませんが、行う必要がある場合は、そこにテーブル名を使用する必要があります。これは、参照が参照されたテーブル名で作成されるためです。上記の例では、複数形(bars)が使用されています。これは、barモデルがデフォルト設定で作成された(基礎となるテーブルを自動的に複数形にする)ことを前提としています。
遅延ロードからデータを取得する場合
クエリでincludeを実行すると、含まれるデータは、次のルールに従って、返されるオブジェクトの追加フィールドに追加されます。
- 単一のアソシエーション(hasOneまたはbelongsTo)から何かを含める場合-フィールド名はモデル名の単数形になります。
- 複数のアソシエーション(hasManyまたはbelongsToMany)から何かを含める場合-フィールド名はモデルの複数形になります。
要するに、フィールドの名前は、各状況で最も論理的な形式を取ります。
例
// Assuming Foo.hasMany(Bar)
const foo = Foo.findOne({ include: Bar });
// foo.bars will be an array
// foo.bar will not exist since it doens't make sense
// Assuming Foo.hasOne(Bar)
const foo = Foo.findOne({ include: Bar });
// foo.bar will be an object (possibly null if there is no associated model)
// foo.bars will not exist since it doens't make sense
// And so on.
エイリアスを定義するときに単数形と複数形をオーバーライドする
アソシエーションのエイリアスを定義するときは、単に{ as: 'myAlias' }を使用する代わりに、単数形と複数形を指定するオブジェクトを渡すことができます。
Project.belongsToMany(User, {
  as: {
    singular: 'líder',
    plural: 'líderes',
  },
});
モデルがアソシエーションで常に同じエイリアスを使用することがわかっている場合は、単数形と複数形をモデル自体に直接提供できます。
const User = sequelize.define(
  'user',
  {
    /* ... */
  },
  {
    name: {
      singular: 'líder',
      plural: 'líderes',
    },
  },
);
Project.belongsToMany(User);
ユーザーインスタンスに追加されたmixinは、正しい形式を使用します。たとえば、project.addUser()の代わりに、Sequelizeはproject.getLíder()を提供します。また、project.setUsers()の代わりに、Sequelizeはproject.setLíderes()を提供します。
注:asを使用してアソシエーションの名前を変更すると、外部キーの名前も変更されることに注意してください。したがって、この場合は、関係する外部キーも直接指定することをお勧めします。
// Example of possible mistake
Invoice.belongsTo(Subscription, { as: 'TheSubscription' });
Subscription.hasMany(Invoice);
上記の最初の呼び出しでは、InvoiceにtheSubscriptionIdという外部キーが設定されます。ただし、2番目の呼び出しでは、Invoiceにも外部キーが設定されます(ご存知のとおり、hasMany呼び出しではターゲットモデルに外部キーが配置されるため)。ただし、名前はsubscriptionIdになります。このようにして、subscriptionId列とtheSubscriptionId列の両方ができます。
最善の方法は、外部キーの名前を選択し、両方の呼び出しに明示的に配置することです。たとえば、subscription_idが選択された場合
// Fixed example
Invoice.belongsTo(Subscription, {
  as: 'TheSubscription',
  foreignKey: 'subscription_id',
});
Subscription.hasMany(Invoice, { foreignKey: 'subscription_id' });