メインコンテンツへスキップ

Prisma ORM MongoDBデータベースコネクタ

このガイドでは、Prisma ORMとMongoDBを使用する際の概念について説明し、MongoDBと他のデータベースプロバイダとの共通点と相違点を解説し、Prisma ORMを使用してMongoDBと統合するためのアプリケーション設定プロセスを案内します。

情報

Prisma ORMをMongoDBに接続するには、入門ドキュメントを参照してください。

MongoDBとは?

MongoDBはNoSQLデータベースで、キーと値のペアでデータを保存するために設計されたJSONライクなドキュメント形式であるBSON形式でデータを格納します。ドキュメントモデルがアプリケーションコードのオブジェクトに容易にマッピングされ、高可用性と水平スケーリングの組み込みサポートがあるため、JavaScriptアプリケーション開発で一般的に使用されます。

MongoDBは、リレーショナルデータベースのテーブルのように事前にスキーマを定義する必要がないコレクションにデータを格納します。各コレクションの構造も時間とともに変更できます。この柔軟性により、データモデルの迅速な反復が可能になりますが、Prisma ORMを使用してMongoDBデータベースを操作する際にはいくつかの違いがあることを意味します。

他のデータベースプロバイダとの共通点

Prisma ORMをMongoDBで使用する際のいくつかの側面は、リレーショナルデータベースでPrisma ORMを使用する場合と同じです。引き続き以下を行うことができます。

考慮すべき違い

MongoDBのドキュメントベースの構造と柔軟なスキーマは、Prisma ORMをMongoDBで使用する場合とリレーショナルデータベースで使用する場合でいくつかの点で異なります。以下は、注意すべき違いがある領域です

  • IDの定義: MongoDBドキュメントには_idフィールドがあり(しばしばObjectIDが含まれます)。Prisma ORMは_で始まるフィールドをサポートしていないため、@map属性を使用してPrisma ORMフィールドにマッピングする必要があります。詳細については、MongoDBでのIDの定義を参照してください。

  • 既存のデータをPrismaスキーマに合わせて移行する: リレーショナルデータベースでは、すべてのデータがスキーマと一致する必要があります。移行時にスキーマの特定のフィールドの型を変更した場合、すべてのデータも更新して一致させる必要があります。対照的に、MongoDBは特定のスキーマを強制しないため、移行時には注意が必要です。詳細については、古いデータを新しいスキーマに移行する方法を参照してください。

  • イントロスペクションとPrisma ORMリレーション: 既存のMongoDBデータベースをイントロスペクションすると、リレーションのないスキーマが得られるため、不足しているリレーションを手動で追加する必要があります。詳細については、イントロスペクション後に不足しているリレーションを追加する方法を参照してください。

  • nullおよび不足フィールドのフィルタリング: MongoDBは、フィールドをnullに設定することと、まったく設定しないことを区別します。これはリレーショナルデータベースには存在しません。Prisma ORMは現在この区別を表現していないため、nullおよび不足フィールドをフィルタリングする際には注意が必要です。詳細については、nullおよび不足フィールドをフィルタリングする方法を参照してください

  • レプリケーションの有効化: Prisma ORMは、ネストされたクエリでの部分的な書き込みを避けるために、内部的にMongoDBトランザクションを使用します。トランザクションを使用する場合、MongoDBはデータセットのレプリケーションが有効になっていることを要求します。これを行うには、レプリカセットを構成する必要があります。これは、同じデータセットを維持するMongoDBプロセスのグループです。単一ノードのレプリカセットを作成することで、単一のデータベースを使用することも可能です。MongoDBのAtlasホスティングサービスを使用する場合、レプリカセットは自動的に構成されますが、MongoDBをローカルで実行している場合は、自分でレプリカセットを設定する必要があります。詳細については、MongoDBのレプリカセットのデプロイガイドを参照してください。

大規模なコレクションにおけるパフォーマンスの考慮事項

問題

Prismaを介して大規模なMongoDBコレクションを操作する場合、特定の操作が遅くなり、リソースを大量に消費することがあります。特に、count()のようにコレクション全体をスキャンする必要がある操作は、クエリ実行時間制限に達し、データセットが大きくなるにつれてパフォーマンスに著しく影響を与える可能性があります。

解決策

大規模なMongoDBコレクションでのパフォーマンス問題を解決するには、次のアプローチを検討してください

  1. 大規模なコレクションの場合、count()の代わりにMongoDBのestimatedDocumentCount()を使用することを検討してください。このメソッドは、コレクションに関するメタデータを使用するため、はるかに高速です。PrismaのrunCommandRawメソッドを使用してこのコマンドを実行できます。

  2. 頻繁にアクセスされるカウントの場合、カウンタキャッシュの実装を検討してください。これには、ドキュメントが追加または削除されるたびに更新する、事前に計算されたカウントを持つ別のドキュメントを維持することが含まれます。

Prisma ORMをMongoDBで使用する方法

このセクションでは、MongoDB固有のステップを必要とするタスクを実行する方法について説明します。

既存のデータをPrismaスキーマに合わせて移行する方法

時間の経過とともにデータベースを移行することは、開発サイクルにおいて重要な部分です。開発中には、Prismaスキーマを更新し(たとえば、新しいフィールドを追加するため)、開発環境のデータベースのデータを更新し、最終的に更新されたスキーマと新しいデータの両方を本番データベースにプッシュする必要があります。

情報

MongoDBを使用する場合、スキーマとデータベース間の「結合」がSQLデータベースよりも意図的に緩く設計されていることに注意してください。MongoDBはスキーマを強制しないため、データの整合性を検証する必要があります。

スキーマとデータベースを反復的に更新するこれらのタスクは、スキーマとデータベース内の実際のデータとの間に不整合をもたらす可能性があります。このような不整合が発生する可能性のあるシナリオを1つ見てから、これらの不整合を処理するためにあなたとあなたのチームが考慮すべきいくつかの戦略を検討しましょう。

シナリオ: ユーザーの電話番号とメールアドレスを含める必要があります。現在、schema.prismaファイルに次のUserモデルがあります

prisma/schema.prisma
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String
}

このスキーマを移行するために使用できるいくつかの戦略があります

  • 「オンデマンド」更新: この戦略では、あなたとあなたのチームは、必要に応じてスキーマの更新が行われることに同意しています。ただし、データとスキーマの不整合による移行の失敗を避けるため、チーム内では、新たに追加されるフィールドは明示的にオプションとして定義されることが合意されています。

    上記のシナリオでは、PrismaスキーマのUserモデルにオプションのphoneNumberフィールドを追加できます

    prisma/schema.prisma
    model User {
    id String @id @default(auto()) @map("_id") @db.ObjectId
    email String
    phoneNumber String?
    }

    次に、npx prisma generateコマンドを使用してPrisma Clientを再生成します。

    次に、新しいフィールドを反映するようにアプリケーションを更新し、アプリを再デプロイします。

    phoneNumberフィールドはオプションであるため、電話番号が定義されていない古いユーザーをクエリできます。データベース内のレコードは、アプリケーションのユーザーが新しいフィールドに電話番号を入力し始めるにつれて「オンデマンド」で更新されます。

    別のオプションは、必須フィールドにデフォルト値を追加することです。たとえば、

    prisma/schema.prisma
    model User {
    id String @id @default(auto()) @map("_id") @db.ObjectId
    email String
    phoneNumber String @default("000-000-0000")
    }

    そうすると、phoneNumberが見つからない場合、値は000-000-0000に強制的に変換されます。

  • 「破壊的変更なし」更新: この戦略は最初の戦略に基づいており、チーム内でさらに、フィールドの名前変更や削除は行わず、新しいフィールドのみを追加し、常に新しいフィールドをオプションとして定義するという合意があります。このポリシーは、CI/CDプロセスに、スキーマに対する後方互換性のない変更がないことを確認するためのチェックを追加することで強化できます。

  • 「一括」更新: この戦略は、すべてのデータが新しいスキーマを反映するように更新されるリレーショナルデータベースにおける従来の移行に似ています。上記のシナリオでは、データベース内のすべての既存ユーザーの電話番号フィールドに値を追加するスクリプトを作成します。スキーマとデータが整合しているため、このフィールドをアプリケーションで必須フィールドに設定できます。

イントロスペクション後に不足しているリレーションを追加する方法

既存のMongoDBデータベースをイントロスペクションした後、モデル間のリレーションを手動で追加する必要があります。MongoDBには、リレーショナルデータベースのように外部キーを介してリレーションを定義するという概念はありません。ただし、MongoDBに、別のコレクションのIDフィールドと一致する「外部キーのような」フィールドを持つコレクションがある場合、Prisma ORMはコレクション間のリレーションをエミュレートすることを可能にします。

例として、UserPostの2つのコレクションを持つMongoDBデータベースを考えます。これらのコレクションのデータは次の形式であり、ユーザーと投稿をリンクするuserIdフィールドがあります

Userコレクション

  • 型がobjectId_idフィールド
  • 型がstringemailフィールド

Postコレクション

  • 型がobjectId_idフィールド
  • 型がstringtitleフィールド
  • 型がobjectIDuserId

db pullによるイントロスペクションでは、これはPrismaスキーマに次のように取り込まれます

prisma/schema.prisma
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
userId String @db.ObjectId
}

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String
}

これはUserモデルとPostモデル間のリレーションが不足しています。これを修正するには、手動でPostモデルにuserフィールドを、fields値としてuserIdを使用し、Userモデルにリンクする@relation属性を追加し、Userモデルに逆リレーションとしてpostsフィールドを追加します

prisma/schema.prisma
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
userId String @db.ObjectId
user User @relation(fields: [userId], references: [id])
}

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String
posts Post[]
}

Prisma ORMでのリレーションの使用方法の詳細については、ドキュメントを参照してください。

nullおよび欠落フィールドのフィルタリング方法

MongoDBがnullと欠落フィールドをどのように区別するかを理解するために、オプションのnameフィールドを持つUserモデルの例を考えてみましょう。

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String
name String?
}

まず、nameフィールドが明示的にnullに設定されたレコードを作成してみてください。Prisma ORMは期待どおりにname: nullを返します

const createNull = await prisma.user.create({
data: {
email: 'user1@prisma.io',
name: null,
},
})
console.log(createNull)
表示CLI結果
{
id: '6242c4ae032bc76da250b207',
email: 'user1@prisma.io',
name: null
}

MongoDBデータベースを直接確認すると、namenullに設定された新しいレコードも確認できます

{
"_id": "6242c4af032bc76da250b207",
"email": "user1@prisma.io",
"name": null
}

次に、nameフィールドを明示的に設定せずにレコードを作成してみてください

const createMissing = await prisma.user.create({
data: {
email: 'user2@prisma.io',
},
})
console.log(createMissing)
表示CLI結果
{
id: '6242c4ae032bc76da250b208',
email: 'user2@prisma.io',
name: null
}

Prisma ORMは引き続きname: nullを返しますが、データベースを直接確認すると、レコードにはnameフィールドがまったく定義されていないことがわかります

{
"_id": "6242c4af032bc76da250b208",
"email": "user2@prisma.io"
}

Prisma ORMはどちらの場合も同じ結果を返します。これは、基盤となるデータベースでnullであるフィールドと、まったく定義されていないフィールドとの間のこの違いをMongoDBで指定する方法が現在ないためです。詳細については、こちらのGithub Issueを参照してください。

これは、現在nullおよび欠落フィールドをフィルタリングする際に注意が必要であることを意味します。name: nullでレコードをフィルタリングすると、nameが明示的にnullに設定された最初のレコードのみが返されます

const findNulls = await prisma.user.findMany({
where: {
name: null,
},
})
console.log(findNulls)
表示CLI結果
[
{
id: '6242c4ae032bc76da250b207',
email: 'user1@prisma.io',
name: null
}
]

これは、name: nullが同等性をチェックしており、存在しないフィールドはnullとは等しくないためです。

欠落しているフィールドも含むには、isSetフィルターを使用して、nullまたは未設定のフィールドを明示的に検索します。これにより、両方のレコードが返されます

const findNullOrMissing = await prisma.user.findMany({
where: {
OR: [
{
name: null,
},
{
name: {
isSet: false,
},
},
],
},
})
console.log(findNullOrMissing)
表示CLI結果
[
{
id: '6242c4ae032bc76da250b207',
email: 'user1@prisma.io',
name: null
},
{
id: '6242c4ae032bc76da250b208',
email: 'user2@prisma.io',
name: null
}
]

MongoDBとPrisma ORMの使用に関する詳細

MongoDBをPrisma ORMで使い始める最も早い方法は、入門ドキュメントを参照することです。

これらのチュートリアルでは、MongoDBへの接続、スキーマ変更のプッシュ、Prisma Clientの使用方法について説明しています。

さらなる参照情報は、MongoDBコネクタのドキュメントで利用可能です。

MongoDBデータベースのセットアップと管理方法の詳細については、Prismaデータガイドを参照してください。

MongoDBサーバーに接続するには、Prismaスキーマ内のdatasourceブロックを設定します

schema.prisma
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}

datasourceブロックに渡されるフィールドは次のとおりです。

  • provider: mongodbデータソースコネクタを指定します。
  • url: MongoDBサーバーの接続URLを指定します。この場合、接続URLを提供するために環境変数が使用されます
警告

MongoDBデータベースコネクタは、ネストされた書き込みをサポートするためにトランザクションを使用します。トランザクションには、レプリカセットのデプロイが必要です。レプリカセットをデプロイする最も簡単な方法は、Atlasを使用することです。無料で開始できます。

接続詳細

接続URL

MongoDB接続URLは、データベースのホスティング方法に応じて異なる方法で構成できます。標準的な構成は、次のコンポーネントで構成されています

Structure of the MongoDB connection URL

ベースURLとパス

接続URLのベースURLとパスのセクションは、認証資格情報とそれに続くホスト(およびオプションでポート番号)とデータベースで構成されています。

mongodb://USERNAME:PASSWORD@HOST/DATABASE

次のコンポーネントがデータベースのベースURLを構成します

名前プレースホルダー説明
ユーザーUSERNAMEデータベースユーザー名(例:janedoe
パスワードPASSWORDデータベースユーザーのパスワード
ホストHOSTmongodインスタンスが実行されているホスト。シャードクラスターを実行している場合は、mongosインスタンスになります。これはホスト名、IPアドレス、またはUNIXドメインソケットです。
ポートPORTデータベースサーバーが実行されているポート(例:1234)。指定されていない場合は、デフォルトの27017が使用されます。
データベースDATABASE使用するデータベース名。指定されていないがauthSourceオプションが設定されている場合は、authSourceデータベース名が使用されます。接続文字列のデータベースもauthSourceオプションも指定されていない場合は、デフォルトでadminになります。
情報

特殊文字はパーセントエンコードする必要があります。

引数

接続URLは引数を取ることもできます。次の例では3つの引数を設定しています

  • ssl接続
  • connectTimeoutMS
  • そしてmaxPoolSize
mongodb://USERNAME:PASSWORD@HOST/DATABASE?ssl=true&connectTimeoutMS=5000&maxPoolSize=50

接続文字列の引数の完全なリストについては、MongoDB接続文字列のドキュメントを参照してください。Prisma ORM固有の引数はありません。

ObjectIdの使用

MongoDBドキュメントの_idフィールドにObjectIdが含まれることは一般的です。

{
"_id": { "$oid": "60d599cb001ef98000f2cad2" },
"createdAt": { "$date": { "$numberLong": "1624611275577" } },
"email": "ella@prisma.io",
"name": "Ella",
"role": "ADMIN"
}

基盤となるデータベースでObjectIdにマッピングされる任意のフィールド(最も一般的にはIDおよびリレーションスカラーフィールド)

  • StringまたはBytes型である必要があります
  • @db.ObjectId属性を含める必要があります
  • オプションで、ドキュメント作成時に有効なObjectIdを自動生成するために@default(auto())を使用できます。

Stringを使用する例は以下のとおりです

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
// Other fields
}

そして、Bytesを使用する別の例は以下のとおりです

model User {
id Bytes @id @default(auto()) @map("_id") @db.ObjectId
// Other fields
}

参照: MongoDBでのIDフィールドの定義

ObjectIdの生成

アプリケーションで有効なObjectIdを生成するには(テスト目的またはIDフィールドの値を手動で設定するため)、bsonパッケージを使用します。

npm install --save bson
import { ObjectId } from 'bson'

const id = new ObjectId()

リレーショナルデータベース用コネクタとの違い

このセクションでは、MongoDBコネクタがリレーショナルデータベース用のPrisma ORMコネクタと異なる点について説明します。

Prisma Migrateの非サポート

現在、Prisma Migrateのサポートを追加する計画はありません。MongoDBプロジェクトは、変更を別のツールで管理する必要がある内部スキーマに依存していないためです。@uniqueインデックスの管理はdb pushを通じて実現されます。

@@idおよびautoincrement()の非サポート

@@id属性(複数のフィールドのID)はサポートされていません。MongoDBの主キーは常にモデルの_idフィールドにあるためです。

autoincrement()関数(インクリメントする@id値を生成する)はサポートされていません。autoincrement()がMongoDBの_idフィールドが持つObjectID型で機能しないためです。

循環参照と参照アクション

モデル内に循環参照がある場合(自己参照またはモデル間のリレーションの循環)、かつ参照アクションを使用している場合、無限ループのアクションを防ぐために、参照アクションをNoActionに設定する必要があります。

詳細については、参照アクションの特別なルールを参照してください。

レプリカセット構成

MongoDBはレプリカセット上でのみトランザクションを開始できます。Prisma ORMは、ネストされたクエリでの部分的な書き込みを避けるために内部的にトランザクションを使用します。これは、レプリカセットが構成されている必要があるという要件を継承することを意味します。

レプリカセットが構成されていないデプロイメントでPrisma ORMのMongoDBコネクタを使用しようとすると、Prisma ORMはError: Transactions are not supported by this deploymentというメッセージを表示します。エラーメッセージの全文は以下のとおりです

PrismaClientUnknownRequestError2 [PrismaClientUnknownRequestError]:
Invalid `prisma.post.create()` invocation in
/index.ts:9:21

6 await prisma.$connect()
7
8 // Create the first post
→ 9 await prisma.post.create(
Error in connector: Database error. error code: unknown, error message: Transactions are not supported by this deployment
at cb (/node_modules/@prisma/client/runtime/index.js:34804:17)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
clientVersion: '3.xx.0'
}

これを解決するには、レプリカセットが構成されたデプロイメントに変更することをお勧めします。

これに対する簡単な方法の1つは、MongoDB Atlasを使用して、最初からレプリカセットのサポートがある無料インスタンスを起動することです。

このガイドに従って、レプリカセットをローカルで実行するオプションもあります: https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set

MongoDBとPrismaスキーマ間の型マッピング

MongoDBコネクタは、Prisma ORMのデータモデルスカラー型をMongoDBのネイティブカラム型に次のようにマッピングします

別の方法として、Prisma型で整理された型マッピングについては、Prismaスキーマ参照を参照してください。

Prisma ORMからMongoDBへのネイティブ型マッピング

Prisma ORMMongoDB
Stringstring
Booleanbool
Intint
BigIntlong
Floatdouble
Decimal現在サポートされていません
DateTimetimestamp
BytesbinData
Json

現在サポートされていないMongoDB型

  • Decimal128
  • Undefined
  • DBPointer
  • Null
  • Symbol
  • MinKey
  • MaxKey
  • Object
  • Javascript
  • JavascriptWithScope
  • Regex

イントロスペクション時のMongoDBからPrisma ORM型へのマッピング

MongoDBデータベースをイントロスペクションする際、Prisma ORMは関連するスカラー型を使用します。一部の特殊な型には、追加のネイティブ型アノテーションも付与されます。

MongoDB(型 | エイリアス)Prisma ORMサポートネイティブデータベース型属性備考
objectIdString✔️@db.ObjectId

イントロスペクションは、まだサポートされていないネイティブデータベース型をUnsupportedフィールドとして追加します。

schema.prisma
model Example {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
regex Unsupported("RegularExpression")
}
© 2025 prisma.dokyumento.jp. All rights reserved.