mongooseはコレクション名の末尾に「s」を付与する

はじめに

mongooseはMongoDB用のアクセスライブラリーだ。
JavaScriptから利用することができる。

TypeScriptを使わない環境下では、2019年現在で最も使われているMongoDB用ライブラリーなのではないだろうか。

このmongooseにはやや理解しづらい「癖」があり、知らないと迷路にはまり込んでしまう。
その「癖」とは、コレクション名の末尾が「s」で終わることを前提としている点にある。

何が起こるのか

例えば利用者の管理用に「user」という名前のコレクションを作成したと想定しよう。
すると驚いたことに、デフォルト状態のmongooseから、このコレクションへアクセスすることはできない。

末尾が「s」ではないからだ。

もちろんMongoDBには、コレクションの末尾が「s」で終わらなければならないなどの制約はない。
これはmongooseが後から追加した制約だ。

回避策は用意されているのだが、控えめに言ってもこれは「勝手な」仕様変更であり、「横暴」と呼んでも過言ではないレベルだ。
アクセスに失敗した時のメッセージも不適切で、原因を突き止めるのに時間がかかりやすくなっている。

対策

この問題への対応案は主に二通りある。
以下で両案の特徴について記述する。

状況と照らし合わせて、より適切な案を採用すればよいだろう。

案1.コレクション名の末尾を「s」にする

こちらの案は、新規にデータベースを設計する場合に向いている。
mongooseの「思想」を受け入れ、それに沿ってコレクション名を設計するのだ。

コレクションはデータの格納庫なので、複数データの存在を想定する場合が多いだろう。
すると末尾の「s」が、英語の複数形の表現と一致し、むしろ分かりやすさに貢献する可能性がある。

利用者管理用のコレクションを「users」と命名することに違和感はないだろう。

欠点としては、やはり命名ルールに制約ができてしまう点だ。
場合によっては、あまり適切ではない名前になってしまう場合もあるだろう。
ルールだから仕方がないと割り切れればよいのだが、利用者の理解を妨げたりストレスに繋がりかねない場合もある。

名前を日本語にしているプロジェクトを時々見かけるが、そのようなチームでは拒絶反応に近い状況を引き起こすかも知れない。
「幅」コレクションが「habas」になったり、「距離」コレクションが「kyoris」になるのは、分かりやすいとは言えない。

名前に英語を使っているプロジェクトでも、複数形の末尾が「s」でないオブジェクトを管理するときに違和感が生じるかも知れない。
「子供」コレクションが「childs」や「childrens」になったり、「知見」コレクションが「 knowledges」になるのを見るのは、あまり落ち着けない。

案2.コレクションに設定を追加する

おすすめの対策はこちらだ。
設定を追加して、コレクション名に対する制約を外してしまうのだ。

具体的な方法は、スキーマの定義にその都度設定を追加する必要があるが、この手間は仕方がないと割り切るしかない。
何よりも一度設定を行えば、二度と問題に煩わされることがなくなる。

具体的な対応方法は、「, { collection: コレクション名 }」の一文をスキーマ定義に追加する。
前出の「user」コレクションの場合だと、例えば以下のようにすればよい。

const userModel: mongoose.Model = mongoose.model(
  'user',
  new mongoose.Schema({
    userId: { type: String },
    userName: { type: String }
  }, { collection: 'user'})
);

この設定を追加すると、「user」のように末尾が「s」でないコレクションにもアクセスが可能になる。
上記はTypeScriptでの例だが、JavaScriptでも基本的には同じだ。

まとめ

mongooseは、コレクション名の末尾に「s」が付いていることを前提としている。
この制約を回避するには、スキーマ定義の最後にコレクション名を指定する以下の一文を追加すればよい。

{ collection : 'コレクション名'}