Firebase Data Connect を使用すると、Google Cloud SQL で管理されている PostgreSQL インスタンスのコネクタを作成できます。これらのコネクタは、スキーマからデータを使用するためのクエリとミューテーションの組み合わせです。
スタートガイドでは、PostgreSQL の映画レビュー アプリのスキーマを紹介しました。
このガイドでは、クエリなどのデプロイ可能な管理オペレーションとアドホック管理オペレーションの両方も紹介しました。
- デプロイ可能なクエリは、クライアント アプリから呼び出すために実装するクエリで、定義した API エンドポイントを使用します。これらは、サーバーにデプロイされたコネクタにバンドルされます。Data Connect ツールは、API に基づいてクライアント SDK を生成します。デプロイされたクエリは IAM ポリシーで保護されないため、Data Connect
@auth
ディレクティブを使用して保護してください。 - アドホック管理クエリは、特権環境から実行されてデータを読み取ります。これらは、Firebase コンソールで作成して実行することも、Data Connect VS Code 拡張機能を使用してローカル開発環境で作成して実行することもできます。
このガイドでは、デプロイ可能なクエリについて詳しく説明します。
Data Connect クエリの機能
Data Connect では、PostgreSQL データベースで想定されるすべての方法で基本的なクエリを実行できます。
しかし、Data Connect の GraphQL 拡張機能を使用すると、高速で効率的なアプリの高度なクエリを実装できます。
- 多くのオペレーションから返されるキー スカラーを使用して、レコードに対する繰り返しオペレーションを簡素化する
- マルチステップ ミューテーション オペレーションの過程でクエリを実行してデータをルックアップし、コード行とサーバーへのラウンド トリップを節約します。
生成されたフィールドを使用してクエリを作成する
Data Connect オペレーションは、スキーマの型と型の関係に基づいて自動的に生成された Data Connect のフィールドのセットを拡張します。これらのフィールドは、スキーマを編集するたびにローカル ツールによって生成されます。
生成されたフィールドを使用すると、単一のテーブルから個々のレコードまたは複数のレコードを取得するクエリから、関連するテーブルから複数のレコードを取得するクエリまで、ますます複雑なクエリを実装できます。スキーマに Movie
型と関連する Actor
型が含まれているとします。Data Connect は、movie
、movies
、actors_on_movies
フィールドなどを生成します。
movie
フィールドを使用したクエリ
|
このフィールドを使用して、キーで 1 つの映画をクエリします。 query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } } |
movies
フィールドを使用したクエリ
|
このフィールドを使用して、複数の映画をクエリします(例: 特定の年のすべての映画)。 query GetMovies($myYear: Int!) { movies(where: { year: { eq: $myYear } }) { title } } |
actors_on_movies
フィールドを使用したクエリ
|
このフィールドを使用して、特定の映画に関連付けられているすべての俳優をクエリします。 query GetActorsOnMovie($myKey: Movie_Key!) { actors_on_movies(where: { movie: { key: { eq: $myKey } } }) { actor { name } } } |
クエリの必須要素
Data Connect クエリは、Data Connect 拡張機能を含む GraphQL クエリです。通常の GraphQL クエリと同様に、オペレーション名と GraphQL 変数のリストを定義できます。
Data Connect は、@auth
などのカスタマイズされたディレクティブを使用して GraphQL クエリを拡張します。
したがって、次のクエリには次のものが含まれます。
query
型の定義ListMoviesByGenre
オペレーション(クエリ)名- 1 つのクエリ引数(ここでは
String
型の$genre
変数) - 単一のディレクティブ
@auth
。 - 単一のフィールド
movies
。
query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
movies(where: { genre: { eq: $genre } }) {
id
title
}
}
すべてのクエリ引数には、型宣言、String
などの組み込み型、Movie
などのカスタムのスキーマ定義型が必要です。
このガイドでは、複雑さを増すクエリのシグネチャについて説明します。最後に、デプロイ可能なクエリの構築に使用できる、強力で簡潔な関係式を紹介します。
クエリ内のキー スカラー
まず、キー スカラーについて説明します。
Data Connect は、各テーブルの主キーを表す特別なキー スカラーを定義します。これは {TableType}_Key で識別されます。これは、主キー値の JSON オブジェクトです。
キー スカラーは、ほとんどの自動生成された読み取りフィールドから返されるレスポンスとして取得するか、スカラーキーの構築に必要なすべてのフィールドを取得したクエリから取得します。
実行例の movie
などの単一の自動クエリは、キー スカラーを受け入れるキー引数をサポートします。
キー スカラーをリテラルとして渡すことができます。ただし、キー スカラーを入力として渡す変数を定義できます。
クエリ
query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } }
レスポンス
{ "data": { "movie": { "title": "Example Movie Title" } } }
これらは、次のようにリクエスト JSON で指定できます(他のシリアル化形式でも指定できます)。
{
# …
"variables": {
"myKey": {"id": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"}
}
}
カスタム スカラー解析により、変数を含むオブジェクト構文を使用して Movie_Key
を構築することもできます。これは、何らかの理由で個々のコンポーネントを異なる変数に分割する場合に特に便利です。
基本的なクエリを作成する
クエリの作成を開始して、データベースから個々のレコードを取得したり、テーブルからレコードを一覧表示したりできます。結果を制限して並べ替えることもできます。
個々のレコードを取得する
最も簡単なクエリは、ID で単一のレコードを取得します。クエリでは、自動生成された movie
フィールドが使用されます。
クエリ
query GetMovieById($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { id title imageUrl genre } }
レスポンス
{ "data": { "movie": { "id": "some-uuid", "title": "Example Movie Title", "imageUrl": "https://example.com/movie.jpg", "genre": "Action" } } }
テーブル内のすべてのレコードを取得する
Movies
テーブルの映画の完全なリストからフィールドのサブセットを取得するには、クエリで自動生成された movies
フィールドを使用します。実装は次のようになります。
クエリ
query ListMovies @auth(level: PUBLIC) { movies { id title imageUrl genre } }
レスポンス
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title", "imageUrl": "https://example.com/movie.jpg", "genre": "Action" }, { "id": "another-uuid", "title": "Another Movie Title", "imageUrl": "https://example.com/another-movie.jpg", "genre": "Comedy" } ] } }
orderBy
、limit
、offset
演算子を使用する
当然のことながら、テーブルからすべてのレコードを一覧表示しても、有用性は限られます。
結果の順序付けとページネーションを実行できます。これらの引数は受け入れられますが、結果では返されません。
ここで、クエリは評価の高い上位 10 件の映画のタイトルを取得します。
クエリ
query MoviesTop10 { movies(orderBy: [{ rating: DESC }], limit: 10) { # graphql: list the fields from the results to return title } }
レスポンス
{ "data": { "movies": [ { "title": "Top Movie 1" }, { "title": "Top Movie 2" }, { "title": "Top Movie 3" } // ... other 7 movies ] } }
たとえば、評価順に並べた映画の 11 ~ 20 番目を取得するユースケースがあります。
クエリ
query Movies11to20 { movies(orderBy: [{ rating: DESC }], limit: 10, offset: 10) { # graphql: list the fields from the results to return title } }
レスポンス
{ "data": { "movies": [ { "title": "Movie 11" }, { "title": "Movie 12" }, { "title": "Movie 13" } // ... other 7 movies ] } }
クエリでエイリアスを使用する
Data Connect は、クエリでの GraphQL エイリアシングをサポートしています。エイリアスを使用すると、クエリの結果で返されるデータの名前を変更できます。1 つの Data Connect クエリで、複数のフィルタや他のクエリ オペレーションを 1 つの効率的なリクエストでサーバーに適用できます。これにより、複数の「サブクエリ」を一度に発行できます。返されるデータセットで名前の競合を回避するには、エイリアスを使用してサブクエリを区別します。
次のクエリでは、式でエイリアス mostPopular
と leastPopular
を使用しています。
クエリ
query ReviewPopularitySpread($genre: String) { mostPopular: review( first: { where: {genre: {eq: $genre}}, orderBy: {popularity: DESC} } ), leastPopular: review( last: { where: {genre: {eq: $genre}}, orderBy: {popularity: DESC} } ) }
レスポンス
{ "data": { "mostPopular": [ { "popularity": 9 } ], "leastPopular": [ { "popularity": 1 } ] } }
クエリフィルタを使用する
Data Connect クエリは、一般的な SQL フィルタと順序付けオペレーションにすべてマッピングされます。
orderBy
演算子を使用して where
でフィルタする
テーブル(およびネストされた関連付け)から一致するすべての行を返します。フィルタに一致するレコードがない場合は、空の配列を返します。
クエリ
query MovieByTopRating($genre: String) { mostPopular: movies( where: { genre: { eq: $genre } }, orderBy: { rating: DESC } ) { # graphql: list the fields from the results to return id title genre description } }
レスポンス
{ "data": { "mostPopular": [ { "id": "some-uuid", "title": "Example Movie Title", "genre": "Action", "description": "A great movie" } ] } }
null 値をテストしてフィルタする
isNull
演算子を使用して、null
値をテストできます。
クエリ
query ListMoviesWithoutDescription { movies(where: { description: { isNull: true }}) { id title } }
レスポンス
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" }, { "id": "another-uuid", "title": "Another Movie Title" } ] } }
その他の演算子については、入力オブジェクト型のリファレンス ガイドをご覧ください。
値の比較でフィルタする
lt
(小なり)や ge
(大なりイコール)などの演算子を使用して、クエリ内の値を比較できます。
クエリ
query ListMoviesByRating($minRating: Int!, $maxRating: Int!) { movies(where: { rating: { ge: $minRating, lt: $maxRating }}) { id title } }
レスポンス
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" }, { "id": "another-uuid", "title": "Another Movie Title" } ] } }
配列フィールドの includes
演算子と excludes
演算子でフィルタする
配列フィールドに指定された項目が含まれていることをテストできます。
次の例は、includes
演算子を示しています。
Data Connect は、includesAll
、excludes
、excludesAll
などをサポートしています。整数、文字列、日付、その他のデータ型の演算子については、リファレンス ドキュメントの _ListFilter
見出しをご覧ください。
クエリ
query ListMoviesByTag($tag: String!) { movies(where: { tags: { includes: $tag }}) { # graphql: list the fields from the results to return id title } }
レスポンス
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" } ] } }
文字列オペレーションと正規表現でフィルタする
クエリでは、正規表現などの一般的な文字列検索と比較演算子を使用できます。効率化のため、ここでは複数のオペレーションをバンドルし、エイリアスで区別しています。
query MoviesTitleSearch($prefix: String, $suffix: String, $contained: String, $regex: String) {
prefixed: movies(where: {title: {startsWith: $prefix}}) {...}
suffixed: movies(where: {title: {endsWith: $suffix}}) {...}
contained: movies(where: {title: {contains: $contained}}) {...}
}
_or
、_and
、_not
演算子のロジックでフィルタする
より複雑なロジックには _or
を使用します。Data Connect は、_and
演算子と _not
演算子もサポートしています。
クエリ
query ListMoviesByGenreAndGenre($minRating: Int!, $genre: String) { movies( where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] } ) { # graphql: list the fields from the results to return title } }
レスポンス
{ "data": { "movies": [ { "title": "Movie Title 1" }, { "title": "Movie Title 2" } ] } }
リレーショナル クエリを作成する
Data Connect クエリは、テーブル間の関係に基づいてデータにアクセスできます。スキーマで定義されたオブジェクト(1 対 1)または配列(1 対多)のリレーションを使用して、ネストされたクエリを作成できます。つまり、1 つのタイプのデータを、ネストされたタイプまたは関連するタイプのデータとともに取得できます。
このようなクエリでは、生成された読み取りフィールドでマジック Data Connect _on_
と _via
構文を使用します。
スキーマのサンプルを確認してください。
多対 1
次に、_on_
構文を示すクエリを見てみましょう。
クエリ
query MyReviews @auth(level: USER) { user(key: {id_expr: "auth.uid"}) { reviews: reviews_on_user { movie { name } rating } } }
レスポンス
{ "data": { "user": { "reviews": [ { "movie": { "name": "Movie Title" }, "rating": 5 } ] } } }
1 対 1
_on_
構文を使用して 1 対 1 のクエリを作成できます。
クエリ
query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { movieMetadatas_on_movie { director } } }
レスポンス
{ "data": { "movie": { "movieMetadatas_on_movie": { "director": "Some Director" } } } }
多対多
多対多クエリでは _via_
構文を使用します。多対多クエリでは、指定された映画の俳優を取得できます。
クエリ
query MoviesActors($id: UUID!) @auth(level: USER) { movie(id: $id) { actors: actors_via_MovieActors { name } } }
レスポンス
{ "data": { "movie": { "actors": [ { "name": "Actor Name" } ] } } }
ただし、エイリアスを使用してより複雑なクエリを作成し、role
に基づいてフィルタリングして、mainActors
と supportingActors
の結果で俳優と関連する映画を取得できます。これは多対多であるため、_via_
構文が使用されます。
クエリ
query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) { movie(id: $movieId) { mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) { name } supportingActors: actors_via_MovieActor( where: { role: { eq: "supporting" } } ) { name } } actor(id: $actorId) { mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) { title } supportingRoles: movies_via_MovieActor( where: { role: { eq: "supporting" } } ) { title } } }
レスポンス
{ "data": { "movie": { "mainActors": [ { "name": "Main Actor Name" } ], "supportingActors": [ { "name": "Supporting Actor Name" } ] }, "actor": { "mainRoles": [ { "title": "Main Role Movie Title" } ], "supportingRoles": [ { "title": "Supporting Role Movie Title" } ] } } }
集約クエリ
集計とは何か、集計を使用する理由
集計フィールドを使用すると、結果のリストに対して計算を実行できます。集計フィールドを使用すると、次のようなことができます。
- レビューの平均スコアを求める
- ショッピング カート内の商品の合計金額を求める
- 評価が最も高い商品または最も低い商品を見つける
- ストア内の商品数を数える
集計はサーバーで行われます。クライアントサイドで計算するよりも、次のようなメリットがあります。
- アプリのパフォーマンスが向上する(クライアントサイドの計算を回避できるため)
- データの下り(外向き)費用が削減される(すべての入力ではなく、集計結果のみを送信するため)。
- セキュリティの強化(クライアントにデータセット全体ではなく集計データへのアクセス権を付与できるため)
集計のスキーマの例
このセクションでは、ストアフロントのサンプル スキーマに切り替えます。これは、集計の使用方法を説明するのに適しています。
type Product @table {
name: String!
manufacturer: String!
quantityInStock: Int!
price: Float!
expirationDate: Date
}
単純な集計
すべてのフィールドの _count
最も単純な集計フィールドは _count
です。これは、クエリに一致する行数を返します。型内の各フィールドに対して、Data Connect はフィールドの型に応じて対応する集計フィールドを生成します。
クエリ
query CountProducts {
products {
_count
}
}
回答one
one
たとえば、データベースに 5 つの商品がある場合、結果は次のようになります。
{
"products": [
{
"_count": 5
}
]
}
すべてのフィールドには <field>_count
フィールドがあり、そのフィールドに null 以外の値がある行の数をカウントします。
クエリ
query CountProductsWithExpirationDate {
products {
expirationDate_count
}
}
レスポンスfield_count
field_count
たとえば、有効期限付きの商品が 3 つある場合、結果は次のようになります。
{
"products": [
{
"expirationDate_count": 3
}
]
}
数値フィールドの _min、_max、_sum、_avg
数値フィールド(int、float、int64)にも <field>_min
、<field>_max
、<field>_sum
、<field>_avg
があります。
クエリ
query NumericAggregates {
products {
quantityInStock_max
price_min
price_avg
quantityInStock_sum
}
}
レスポンス_min _max _sum _avg
_min _max _sum _avg
たとえば、次の商品があるとします。
- 商品 A:
quantityInStock: 10
、price: 2.99
- プロダクト B:
quantityInStock: 5
、price: 5.99
- プロダクト C:
quantityInStock: 20
、price: 1.99
結果は次のようになります。
{
"products": [
{
"quantityInStock_max": 20,
"price_min": 1.99,
"price_avg": 3.6566666666666666,
"quantityInStock_sum": 35
}
]
}
日付とタイムスタンプの _min と _max
日付とタイムスタンプのフィールドには <field>_min
と <field>_max
があります。
クエリ
query DateAndTimeAggregates {
products {
expirationDate_max
expirationDate_min
}
}
レスポンス_min _maxdatetime
_min _maxdatetime
たとえば、次のような有効期限があるとします。
- 商品 A:
2024-01-01
- 商品 B:
2024-03-01
- 商品 C:
2024-02-01
結果は次のようになります。
{
"products": [
{
"expirationDate_max": "2024-03-01",
"expirationDate_min": "2024-01-01"
}
]
}
Distinct
distinct
引数を使用すると、フィールド(またはフィールドの組み合わせ)の一意の値をすべて取得できます。例:
クエリ
query ListDistinctManufacturers {
products(distinct: true) {
manufacturer
}
}
レスポンスdistinct
distinct
たとえば、次のメーカーがあるとします。
- 商品 A:
manufacturer: "Acme"
- 商品 B:
manufacturer: "Beta"
- 商品 C:
manufacturer: "Acme"
結果は次のようになります。
{
"products": [
{ "manufacturer": "Acme" },
{ "manufacturer": "Beta" }
]
}
集計フィールドで distinct
引数を使用して、個別の値を集計することもできます。例:
クエリ
query CountDistinctManufacturers {
products {
manufacturer_count(distinct: true)
}
}
レスポンスdistinctonaggregate
distinctonaggregate
たとえば、次のメーカーがあるとします。
- 商品 A:
manufacturer: "Acme"
- 商品 B:
manufacturer: "Beta"
- 商品 C:
manufacturer: "Acme"
結果は次のようになります。
{
"products": [
{
"manufacturer_count": 2
}
]
}
グループ化された集計
グループ化された集計を実行するには、型で集計フィールドと非集計フィールドを組み合わせて選択します。これにより、集計以外のフィールドの値が同じ一致する行がすべてグループ化され、そのグループの集計フィールドが計算されます。例:
クエリ
query MostExpensiveProductByManufacturer {
products {
manufacturer
price_max
}
}
レスポンスgroupedaggregates
groupedaggregates
たとえば、次の商品があるとします。
- 商品 A:
manufacturer: "Acme"
、price: 2.99
- プロダクト B:
manufacturer: "Beta"
、price: 5.99
- プロダクト C:
manufacturer: "Acme"
、price: 1.99
結果は次のようになります。
{
"products": [
{ "manufacturer": "Acme", "price_max": 2.99 },
{ "manufacturer": "Beta", "price_max": 5.99 }
]
}
グループ化された集計を含む having
と where
having
引数と where
引数を使用して、指定した条件を満たすグループのみを返すこともできます。
having
を使用すると、集計フィールドでグループをフィルタできますwhere
を使用すると、集計以外のフィールドに基づいて行をフィルタリングできます。
クエリ
query FilteredMostExpensiveProductByManufacturer {
products(having: {price_max: {ge: 2.99}}) {
manufacturer
price_max
}
}
レスポンスhavingwhere
havingwhere
たとえば、次の商品があるとします。
- 商品 A:
manufacturer: "Acme"
、price: 2.99
- プロダクト B:
manufacturer: "Beta"
、price: 5.99
- プロダクト C:
manufacturer: "Acme"
、price: 1.99
結果は次のようになります。
{
"products": [
{ "manufacturer": "Acme", "price_max": 2.99 },
{ "manufacturer": "Beta", "price_max": 5.99 }
]
}
テーブル間の集計
集計フィールドは、生成された一対多のリレーションシップ フィールドと組み合わせて使用することで、データに関する複雑な質問に回答できます。次に、例で使用できる個別のテーブル Manufacturer
を含む変更されたスキーマを示します。
type Product @table {
name: String!
manufacturer: Manufacturer!
quantityInStock: Int!
price: Float!
expirationDate: Date
}
type Manufacturer @table {
name: String!
headquartersCountry: String!
}
集計フィールドを使用して、メーカーが製造している製品の数を調べるなどの操作を行うことができます。
クエリ
query GetProductCount($id: UUID) {
manufacturers {
name
products_on_manufacturer {
_count
}
}
}
回答aggregatesacrosstables
aggregatesacrosstables
たとえば、次のメーカーがあるとします。
- メーカー A:
name: "Acme"
、products_on_manufacturer: 2
- メーカー B:
name: "Beta"
、products_on_manufacturer: 1
結果は次のようになります。
{
"manufacturers": [
{ "name": "Acme", "products_on_manufacturer": { "_count": 2 } },
{ "name": "Beta", "products_on_manufacturer": { "_count": 1 } }
]
}
高度なクエリを作成する: query
フィールドを使用して、複数ステップのオペレーションでデータを読み取る
たとえば、挿入や更新を行う前に、ミューテーションの実行中にデータベースを読み取って既存のデータを検索し、検証したい状況はたくさんあります。これらのオプションを使用すると、ラウンド トリップ オペレーションが節約され、コストが削減されます。
Data Connect はこの機能をサポートしています。複数ステップのオペレーションをご覧ください。
次のステップ
関連情報: