🌲

【NestJS】mongooseでクラスとDBのコレクションのフィールド名を分けたい

2023/01/11に公開

概要

NestJSでMongoDBに接続する方法として、mongooseというライブラリを使用するという手段が挙げられます。mongooseの導入方法はこちらのNestJSのドキュメントにあるのですが、Model injectionの項に書いてある実装だと、Schemaのクラスで指定したフィールド名が、そのままDBのコレクションのフィールド名として使われてしまいます。
クラスとDBのフィールド名を、別で管理したいどうするかというのをメモ書きします。

前提など

  • NestJSのバージョンは8.2.6を使用しています。
  • mongooseのバージョンは6.8.3を使用しています。
  • nestjs/mongooseのバージョンは9.2.1を使用しています。

対応方針

上記の概要で紹介したNestJSのmongooseドキュメントのModel injectionの項の下部に、define a schema manuallyの記述があり、schemaのフィールド名を手動で設定することができます。
クラスのフィールド名とどう紐づけるかというと、mongooseのドキュメントAliasesにある通り、schemaにalias設定を追加することで実現できそうです。

実装サンプル

まずはschemaの設定です。
今回はDBの_idのaliasとしてobjectIduser_nameのaliasとしてuserNameを設定しています。

import mongoose, { HydratedDocument } from 'mongoose';
import { v4 as uuidv4 } from 'uuid';

export const USER_ACCOUNT_SCHEMA_NAME = 'user_account';

// DBのスキーマ設定
export const UserAccountSchema = new mongoose.Schema(
  {
    _id: {
      type: String,
      alias: 'objectId',
      default: uuidv4(),
    },
    user_name: {
      type: String,
      required: true,
      alias: 'userName',
    },
    description: {
      type: String,
    },
  },
  { collection: USER_ACCOUNT_SCHEMA_NAME },
);

// データの受け渡しで使用するクラス
export class UserAccountModel {
  public objectId?: string;

  public userName: string;

  public description?: string;

  constructor(
    userName: string,
    description?: string,
    objectId?: string,
  ) {
    this.objectId = objectId;
    this.userName = userName;
    this.description = description;
  }
}

export type UserAccountDocument = HydratedDocument<UserAccountModel>;

DBの更新・取得部分の実装です。

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import {
  UserAccountDocument,
  UserAccountModel,
  USER_ACCOUNT_SCHEMA_NAME,
} from '../Model/Mongo/userAccount/userAccount.schema';

@Injectable()
export class UserAccountRepository {
  constructor(
    @InjectModel(USER_ACCOUNT_SCHEMA_NAME)
    private userAccountModel: Model<UserAccountDocument>,
  ) {}

  async createUserAccount(
    userName: string,
    description?: string,
  ): Promise<UserAccountModel> {
    return await this.userAccountModel.create(
      new UserAccountModel(userName, description),
    );
  }

  async findByObjectId(objectId: string): Promise<UserAccountModel> {
    // クエリの条件部分はDBのフィールド名で指定する。
    return await this.userAccountModel.findOne({ _id: objectId });
  }

}

最後にModuleの設定部分の実装です。

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserAccountRepository } from '../Repository/userAccount.repository';
import {
  UserAccountSchema,
  USER_ACCOUNT_SCHEMA_NAME,
} from '../Model/Mongo/userAccount/userAccount.schema';

@Module({
  imports: [
    // スキーマ設定を追加する
    MongooseModule.forFeature([
      { name: USER_ACCOUNT_SCHEMA_NAME, schema: UserAccountSchema },
    ]),
  ],
  controllers: [UserAccountController],
  providers: [UserAccountRepository],
})

export class UserAccountModule {}

Discussion