ビュー
データベースビューを使用すると、クエリに名前を付けて保存できます。リレーショナルデータベースでは、ビューは保存されたSQLクエリであり、複数のテーブルの列や集計などの計算値を含む場合があります。MongoDBでは、ビューは、他のコレクションに対する集約パイプラインによって内容が定義されるクエリ可能なオブジェクトです。
`views`プレビュー機能を使用すると、`view`キーワードを使用してPrismaスキーマにビューを表現できます。Prisma ORMでビューを使用するには、以下の手順に従ってください。
- `views`プレビュー機能を有効にする
- 基盤となるデータベースでビューを作成します(直接またはPrisma Migrateマイグレーションファイルへの手動追加として)、または既存のビューを使用します
- Prismaスキーマでビューを表現する
- Prismaクライアントでビューをクエリする
`views`プレビュー機能を有効にする
ビューのサポートは現在、早期プレビュー段階にあります。`views`プレビュー機能を有効にするには、Prismaスキーマの`generator`ブロックにある`previewFeatures`フィールドに`views`機能フラグを追加してください。
generator client {
provider = "prisma-client-js"
previewFeatures = ["views"]
}
このプレビュー機能に関するフィードバックは、専用の`views`プレビュー機能フィードバック課題にお寄せください。
基盤となるデータベースでビューを作成する
現在、Prismaスキーマで定義したビューをPrisma Migrateや`db push`でデータベースに適用することはできません。代わりに、まず基盤となるデータベースにビューを手動で、またはマイグレーションの一部として作成する必要があります。
例えば、`User`モデルと関連する`Profile`モデルを持つ以下のPrismaスキーマを考えます。
- リレーショナルデータベース
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
bio String
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
profile Profile?
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
bio String
User User @relation(fields: [userId], references: [id])
userId String @unique @db.ObjectId
}
次に、`User`モデルの`email`と`name`フィールド、および`Profile`モデルの`bio`フィールドを組み合わせた、基盤となるデータベース内の`UserInfo`ビューを考えます。
リレーショナルデータベースの場合、このビューを作成するためのSQLステートメントは次のとおりです。
CREATE VIEW "UserInfo" AS
SELECT u.id, email, name, bio
FROM "User" u
LEFT JOIN "Profile" p ON u.id = p."userId";
MongoDBの場合、以下のコマンドでビューを作成できます。
db.createView('UserInfo', 'User', [
{
$lookup: {
from: 'Profile',
localField: '_id',
foreignField: 'userId',
as: 'ProfileData',
},
},
{
$project: {
_id: 1,
email: 1,
name: 1,
bio: '$ProfileData.bio',
},
},
{ $unwind: '$bio' },
])
Prisma Migrateと`db push`でビューを使用する
Prisma Migrateまたは`db push`でPrismaスキーマに変更を適用しても、Prisma ORMはビューに関連するSQLを作成したり実行したりしません。
ビューをマイグレーションに含めるには、`migrate dev --create-only`を実行してから、ビュー用のSQLを手動でマイグレーションファイルに追加します。または、データベースでビューを手動で作成することもできます。
Prismaスキーマにビューを追加する
Prismaスキーマにビューを追加するには、`view`キーワードを使用します。
上記の例の`UserInfo`ビューは、Prismaスキーマで次のように表現できます。
- リレーショナルデータベース
- MongoDB
view UserInfo {
id Int @unique
email String
name String
bio String
}
view UserInfo {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String
name String
bio String
}
手書きで記述
`view`ブロックは主に2つの要素で構成されます。
- `view`ブロック定義
- ビューのフィールド定義
これら2つの要素により、生成されるPrismaクライアントでのビューの名前と、ビューのクエリ結果に存在する列を定義できます。
`view`ブロックを定義する
上記の例から`UserInfo`ビューを定義するには、まず`view`キーワードを使用して、スキーマ内で`UserInfo`という名前の`view`ブロックを定義します。
view UserInfo {
// Fields
}
フィールドの定義
ビューのプロパティは*フィールド*と呼ばれ、以下で構成されます。
- フィールド名
- フィールド型
`UserInfo`の例のビューのフィールドは、次のように定義できます。
- リレーショナルデータベース
- MongoDB
view UserInfo {
id Int @unique
email String
name String
bio String
}
view UserInfo {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String
name String
bio String
}
`view`ブロックの各*フィールド*は、基盤となるデータベースのビューのクエリ結果における列を表します。
イントロスペクションを使用する
現在、PostgreSQL、MySQL、SQL Server、CockroachDBでのみ利用可能です。
データベースに既存のビューが定義されている場合、イントロスペクションにより、それらのビューを表す`view`ブロックがPrismaスキーマに自動的に生成されます。
基盤となるデータベースに例の`UserInfo`ビューが存在すると仮定すると、以下のコマンドを実行すると、そのビューを表す`view`ブロックがPrismaスキーマに生成されます。
npx prisma db pull
結果として生成される`view`ブロックは、次のように定義されます。
/// The underlying view does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client.
view UserInfo {
id Int?
email String?
name String?
bio String?
@@ignore
}
`view`ブロックは、最初は`@@ignore`属性付きで生成されます。これは、一意の識別子が定義されていないため(これは現在、ビュープレビュー機能の制限です)。
現時点では、`db pull`はPostgreSQL、MySQL、SQL Server、またはCockroachDBを使用している場合にのみスキーマ内のビューをイントロスペクトすることに注意してください。このワークフローのサポートは、他のデータベースプロバイダーにも拡張される予定です。
イントロスペクトされたビューに一意の識別子を追加する
イントロスペクトされたビューをPrismaクライアントで使用できるようにするには、1つまたは複数のフィールドを一意の識別子として選択して定義する必要があります。
上記のビューの場合、`id`列は基盤となる`User`テーブルの一意に識別可能なフィールドを参照するため、そのフィールドも`view`ブロックの一意に識別可能なフィールドとして使用できます。
この`view`ブロックを有効にするには、以下の操作が必要です。
- `id`フィールドから*オプション*フラグ`?`を削除する
- `id`フィールドに`@unique`属性を追加する
- `@@ignore`属性を削除する
- 無効なビューに関する生成されたコメント警告を削除する
/// The underlying view does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client.
view UserInfo {
id Int?
id Int @unique
email String?
name String?
bio String?
@@ignore
}
データベースを再イントロスペクトしても、ビュー定義へのカスタム変更は保持されます。
`views`ディレクトリ
1つ以上の既存のビューを持つデータベースのイントロスペクションを行うと、`prisma`ディレクトリ内に新しい`views`ディレクトリも作成されます(Prismaバージョン4.12.0以降)。このディレクトリには、データベースのスキーマ名が付いたサブディレクトリが含まれ、そのスキーマでイントロスペクトされた各ビューの`.sql`ファイルが格納されます。各ファイルは個々のビューの名前にちなんで名付けられ、関連するビューが定義するクエリが含まれます。
例えば、上記のモデルを使用してデフォルトの`public`スキーマを持つデータベースをイントロスペクトすると、`prisma/views/public/UserInfo.sql`ファイルが作成され、その内容は以下のようになります。
SELECT
u.id,
u.email,
u.name,
p.bio
FROM
(
"User" u
LEFT JOIN "Profile" p ON ((u.id = p."userId"))
);
制限事項
一意の識別子
現在、Prisma ORMはビューをモデルと同じように扱います。これは、ビューに少なくとも1つの*一意の識別子*が必要であることを意味します。これは以下のいずれかによって表現できます。
- `@unique`で示されるユニーク制約
- `@@unique`で示される複合ユニーク制約
- `@id`フィールド
- `@@id`で示される複合識別子
リレーショナルデータベースでは、ビューの一意の識別子は、1つのフィールドに`@unique`属性として、または複数のフィールドに`@@unique`属性として定義できます。可能な場合、`@id`または`@@id`フィールドよりも`@unique`または`@@unique`制約を使用することが望ましいです。
しかし、MongoDBでは、一意の識別子は`@map("_id")`で基盤となるデータベースの`_id`フィールドにマップされる`@id`属性である必要があります。
上記の例では、`id`フィールドに`@unique`属性があります。もし基盤となる`User`テーブルの別の列が一意に識別可能として定義され、ビューのクエリ結果で利用可能であったなら、その列を一意の識別子として使用することもできました。
イントロスペクション
現在、ビューのイントロスペクションはPostgreSQL、MySQL、SQL Server、CockroachDBでのみ利用可能です。他のデータベースプロバイダーを使用している場合は、ビューを手動で追加する必要があります。
これは一時的な制限であり、イントロスペクションのサポートは他のサポートされているデータソースプロバイダーにも拡張される予定です。
Prismaクライアントでビューをクエリする
Prismaクライアントでは、モデルをクエリするのと同じ方法でビューをクエリできます。例えば、以下のクエリは、上記で定義された`UserInfo`ビューにおいて`name`が`'Alice'`であるすべてのユーザーを検索します。
const userinfo = await prisma.userInfo.findMany({
where: {
name: 'Alice',
},
})
現在、Prisma Clientでは、基盤となるデータベースが許可していれば、追加の検証なしにビューを更新できます。
特殊なビューの種類
このセクションでは、データベース内の更新可能ビューとマテリアライズドビューでPrisma ORMを使用する方法について説明します。
更新可能ビュー
一部のデータベースは更新可能なビューをサポートしています(例:PostgreSQL、MySQL、SQL Server)。更新可能ビューでは、エントリの作成、更新、削除が可能です。
現在、Prisma ORMはすべての`view`を更新可能なビューとして扱います。基盤となるデータベースがそのビューに対してこの機能をサポートしている場合、操作は成功します。ビューが更新可能とマークされていない場合、データベースはエラーを返し、Prismaクライアントはそれをスローします。
将来的には、Prismaクライアントが個々のビューを更新可能または更新不可としてマークする機能をサポートする可能性があります。ご自身のユースケースを、`views`フィードバック課題にコメントしてください。
マテリアライズドビュー
一部のデータベースはマテリアライズドビューをサポートしています。例: PostgreSQL、CockroachDB、MongoDB、SQL Server(「インデックス付きビュー」と呼ばれます)。
マテリアライズドビューは、ビュークエリの結果を永続化してアクセスを高速化し、必要に応じてのみ更新します。
現在、Prisma ORMはマテリアライズドビューをサポートしていません。ただし、ビューを手動で作成する場合、基盤となるデータベースで対応するコマンドを使用してマテリアライズドビューを作成することもできます。その後、Prisma ClientのTypedSQL機能を使用して、コマンドを実行し、ビューを手動で更新できます。
将来的には、Prismaクライアントが個々のビューをマテリアライズドとしてマークし、マテリアライズドビューをリフレッシュするためのPrismaクライアントメソッドを追加する可能性があります。ご自身のユースケースを、`views`フィードバック課題にコメントしてください。