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
欄位查詢
|
使用這個欄位,依鍵查詢單一電影。 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
作業 (查詢) 名稱- 單一查詢引數,這裡為
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 別名。別名可重新命名查詢結果中傳回的資料。單一Data Connect查詢可透過一個有效率的要求,向伺服器套用多個篩選器或其他查詢作業,一次發出多個「子查詢」。為避免傳回的資料集發生名稱衝突,請使用別名區分子查詢。
以下查詢的運算式使用別名 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" } ] } }
測試空值並據此篩選
您可以使用 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 查詢可根據資料表之間的關係存取資料。您可以使用結構定義中定義的物件 (一對一) 或陣列 (一對多) 關係,進行巢狀查詢,也就是擷取某種型別的資料,以及巢狀或相關型別的資料。
這類查詢會在產生的讀取欄位中使用 Magic Data Connect _on_
和 _via
語法。
請記得查看範例結構定義。
多對一
現在請查看查詢,瞭解 _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 } ] } } }
一對一
您可以使用 _on_
語法撰寫一對一查詢。
查詢
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
欄位,可計算該欄位中有非空值的資料列數量。
查詢
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
引數可讓您取得欄位 (或欄位組合) 的所有不重複值。例如:
查詢
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 支援這項功能。 請參閱多步驟作業。
後續步驟
你可能感興趣的內容: