TypeORMの0.2系で複数のDBを使用する

4353 ワード

ORMにTypeORMの0.2系を採用したAPIサーバにて、2つのDBを使用(参照のみ)する設定方法を備忘録として残します。
最新の0.3系では設定方法が異なるようなので、公式ドキュメントをご参照ください。

確認した環境

  • TypeORM 0.2.29
  • Node.js 14系
  • Express.js + TypeScriptのAPIサーバ

データベースの接続設定

TypeORMのConnectionOptionの設定を配列とすることで、複数のDBの設定を書けます。
どのDBを使うか判別する識別子としてnameを付与します。
なお、片方(一つ目)のDBにnameを設定しなくても動作しました。

ormconfig.ts

import { ConnectionOptions } from "typeorm";

const ormconfig: ConnectionOptions[] = [
  {
    type: "mysql",
    host: process.env.DB_HOST,
    port: Number(process.env.DB_PORT ?? 3306),
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DATABASE,
    synchronize: false,
    logging: false,
    entities: ["src/entities/**/*.ts"],
    migrations: ["src/db/migrations/**/*.ts"],
    subscribers: ["src/db/subscribers/**/*.ts"],
    cli: {
      entitiesDir: "src/entities",
      migrationsDir: "src/db/migrations",
      subscribersDir: "src/db/subscribers",
    },
  },
  {
    name: "db2", // 2つ目のDBの識別子
    type: "postgres",
    host: process.env.DB2_HOST,
    port: Number(process.env.DB2_PORT ?? 5432),
    username: process.env.DB2_USERNAME,
    password: process.env.DB2_PASSWORD,
    database: process.env.DB2_DATABASE,
    synchronize: false,
    logging: false,
    schema: process.env.DB2_SCHEMA,
    entities: ["src/db2Entities/**/*.ts"],
    cli: {
      entitiesDir: "src/db2Entities",
    },
  },
];

export default ormconfig;

今回、2つ目のDBは参照のみ行うため、migrationファイルを作らないように migrations を指定していません。
また、Entity用のディレクトリを1つ目のDBとディレクトリを分けておきます。
ディレクトリ名は適当です。適切なディレクトリ名でお願いします。

接続設定の読み込み

接続設定の読み込みとしてormconfig.tsで指定した識別子を指定します。

index.ts

import { getConnectionOptions, createConnection } from "typeorm";
import express from "express";
import "reflect-metadata";

const main = async () => {
  // 1つ目のDBの接続設定
  const connectionOptions = await getConnectionOptions(); // 引数に何も指定しなくても1つ目のDBと接続できる
  await createConnection(connectionOptions);

  // 2つ目のDBの接続設定
  const connectionOptions2 = await getConnectionOptions("db2"); // 引数に2つ目のDBの識別子を指定する
  await createConnection(connectionOptions2);
  ...

Entityの用意

User.ts

import { Entity, Column, PrimaryColumn } from "typeorm";

@Entity()
export default class User {
  @PrimaryColumn()
  id!: number;

  @Column({ type: "varchar" })
  name!: string;
}

SQL発行

Repository, EntityManagerどちらも、引数に指定した識別子のDBにSQLを発行できます。

Repository APIを使う場合

const db1Repository = getRepository(User);
const result = await db1Repository.find(); // => 引数に何も指定しない場合、1つ目のDBから取得できる

const db2Repository = getRepository(User, "db2"); // => 第二引数にdb2の識別子を指定
const result = await db2Repository.find(); // => 2つ目のDBから取得できる

EntityManager API を使う場合

await getManager("db2").transaction( // => 引数にdb2の識別子を指定
  async (transactionalEntityManager) => {
    const result = await transactionalEntityManager.find(User);  // => 2つ目のDBから取得できる
  }
);

感想

片方の(1つ目の)DBの識別子は省略可能でしたが、サボらずに両方のDBに識別子をつけるべきなんですかね。
既にgetRepository が多く書かれており、全てに設定を入れる必要があるので。。。。。サボらずやります。

ちなみに、TypeORM の0.3系ではormconfigが仕様からdropされており、代わりとなるDataSource を使ったMultiple DBへの接続例が載ってます。