Firebase Data Connect ti consente di creare connettori per le tue istanze PostgreSQL gestite con Google Cloud SQL. Questi connettori sono combinazioni di query e mutazioni per utilizzare i dati dello schema.
La Guida introduttiva ha introdotto uno schema di app di recensioni di film per PostgreSQL.
Questa guida ha introdotto anche operazioni amministrative deployable e ad hoc, incluse le query.
- Le query implementabili sono quelle che implementi per chiamare dalle app client, con gli endpoint API che definisci. Li raggruppi in un connettore
di cui viene eseguito il deployment sul server. Gli strumenti Data Connect generano SDK client
in base alla tua API. Le query di cui è stato eseguito il deployment non sono protette dalle norme IAM, quindi assicurati di proteggerle utilizzando la direttiva Data Connect
@auth
. - Le query amministrative ad hoc vengono eseguite da ambienti privilegiati per leggere i dati. Puoi crearli ed eseguirli nella console Firebase o in ambienti di sviluppo locali utilizzando la nostra estensione VS Code Data Connect.
Questa guida esamina più da vicino le query implementabili.
Funzionalità delle query Data Connect
Data Connect ti consente di eseguire query di base in tutti i modi che ti aspetteresti da un database PostgreSQL.
Ma con le estensioni di GraphQL di Data Connect, puoi implementare query avanzate per app più veloci ed efficienti:
- Utilizza gli scalari chiave restituiti da molte operazioni per semplificare le operazioni ripetute sui record
- Esegui query nel corso di operazioni di mutazione in più passaggi per cercare dati, risparmiando righe di codice e round trip al server.
Utilizzare i campi generati per creare query
Le operazioni Data Connect estenderanno un insieme di campi generati automaticamente Data Connect in base ai tipi e alle relazioni tra i tipi nello schema. Questi campi vengono generati dagli strumenti locali ogni volta che modifichi lo schema.
Puoi utilizzare i campi generati per implementare query sempre più complesse, dal recupero di singoli record o più record da singole tabelle a più record da tabelle correlate.Supponiamo che lo schema contenga un tipo Movie
e un tipo Actor
associato.
Data Connect genera i campi movie
, movies
,
actors_on_movies
e altri ancora.
Query con il campo
movie
Il campo |
Utilizza questo campo per eseguire query su un singolo film in base alla relativa chiave. query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } } |
Query con il campo
movies
Il campo |
Utilizza questo campo per eseguire query su più film, ad esempio tutti i film di un determinato anno. query GetMovies($myYear: Int!) { movies(where: { year: { eq: $myYear } }) { title } } |
Query con il campo
actors_on_movies
Il campo |
Utilizza questo campo per eseguire query su tutti gli attori associati a un determinato film. query GetActorsOnMovie($myKey: Movie_Key!) { actors_on_movies(where: { movie: { key: { eq: $myKey } } }) { actor { name } } } |
Elementi essenziali di una query
Le query Data Connect sono query GraphQL con estensioni Data Connect. Proprio come per una normale query GraphQL, puoi definire un nome dell'operazione e un elenco di variabili GraphQL.
Data Connect estende le query GraphQL con direttive personalizzate come
@auth
.
Pertanto, la seguente query ha:
- Definizione del tipo
query
- Nome di un'operazione (query)
ListMoviesByGenre
- Un singolo argomento della query, in questo caso una variabile
$genre
di tipoString
- Una singola direttiva,
@auth
. - Un singolo campo,
movies
.
query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
movies(where: { genre: { eq: $genre } }) {
id
title
}
}
Ogni argomento della query richiede una dichiarazione di tipo, un tipo integrato come String
o un tipo personalizzato definito dallo schema come Movie
.
Questa guida esamina la firma di query sempre più complesse. Concluderemo presentando espressioni di relazione potenti e concise che puoi utilizzare per creare le query implementabili.
Scalari chiave nelle query
Ma prima, una nota sugli scalari chiave.
Data Connect definisce uno scalare chiave speciale per rappresentare le chiavi primarie di ogni tabella, identificate da {TableType}_Key. È un oggetto JSON di valori della chiave primaria.
Recuperi gli scalari chiave come risposta restituita dalla maggior parte dei campi di lettura generati automaticamente o, naturalmente, dalle query in cui hai recuperato tutti i campi necessari per creare la chiave scalare.
Le query automatiche singolari, come movie
nel nostro esempio in esecuzione, supportano un argomento chiave che accetta uno scalare chiave.
Potresti passare uno scalare chiave come valore letterale. Tuttavia, puoi definire variabili per passare gli scalari delle chiavi come input.
Query
query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } }
Risposta
{ "data": { "movie": { "title": "Example Movie Title" } } }
Questi possono essere forniti in JSON di richiesta come questo (o altri formati di serializzazione):
{
# …
"variables": {
"myKey": {"id": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"}
}
}
Grazie all'analisi scalare personalizzata, è possibile creare anche un Movie_Key
utilizzando la sintassi
dell'oggetto, che può contenere variabili. Questa opzione è utile soprattutto quando vuoi
dividere i singoli componenti in variabili diverse per qualche motivo.
Scrivere query di base
Puoi iniziare a scrivere query per ottenere singoli record dal tuo database oppure elencare i record di una tabella con l'opzione per limitare e ordinare i risultati.
Recuperare singoli record
La query più semplice recupera un singolo record per ID. La query utilizzerà il campo
movie
generato automaticamente.
Query
query GetMovieById($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { id title imageUrl genre } }
Risposta
{ "data": { "movie": { "id": "some-uuid", "title": "Example Movie Title", "imageUrl": "https://example.com/movie.jpg", "genre": "Action" } } }
Recuperare tutti i record in una tabella
Per recuperare un sottoinsieme di campi per l'elenco completo dei film dalla tabella Movies
, la query utilizzerà il campo movies
generato automaticamente e l'implementazione potrebbe essere simile alla seguente.
Query
query ListMovies @auth(level: PUBLIC) { movies { id title imageUrl genre } }
Risposta
{ "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" } ] } }
Utilizzare gli operatori orderBy
, limit
e offset
Naturalmente, elencare tutti i record di una tabella ha un'utilità limitata.
Puoi ordinare ed eseguire l'impaginazione dei risultati. Questi argomenti vengono accettati ma non restituiti nei risultati.
Qui, la query recupera i titoli dei 10 film con la valutazione più alta.
Query
query MoviesTop10 { movies(orderBy: [{ rating: DESC }], limit: 10) { # graphql: list the fields from the results to return title } }
Risposta
{ "data": { "movies": [ { "title": "Top Movie 1" }, { "title": "Top Movie 2" }, { "title": "Top Movie 3" } // ... other 7 movies ] } }
Potresti avere un caso d'uso per recuperare righe da un offset, ad esempio i film da 11 a 20 ordinati in base alla classificazione.
Query
query Movies11to20 { movies(orderBy: [{ rating: DESC }], limit: 10, offset: 10) { # graphql: list the fields from the results to return title } }
Risposta
{ "data": { "movies": [ { "title": "Movie 11" }, { "title": "Movie 12" }, { "title": "Movie 13" } // ... other 7 movies ] } }
Utilizzare gli alias nelle query
Data Connect supporta l'assegnazione di alias GraphQL nelle query. Con gli alias, puoi rinominare i dati restituiti nei risultati di una query. Una singola query Data Connect può applicare più filtri o altre operazioni di query in un'unica richiesta efficiente al server, eseguendo di fatto più "query secondarie" contemporaneamente. Per evitare conflitti di nomi nel set di dati restituito, utilizza gli alias per distinguere le sottoquery.
Ecco una query in cui un'espressione utilizza gli alias mostPopular
e
leastPopular
.
Query
query ReviewPopularitySpread($genre: String) { mostPopular: review( first: { where: {genre: {eq: $genre}}, orderBy: {popularity: DESC} } ), leastPopular: review( last: { where: {genre: {eq: $genre}}, orderBy: {popularity: DESC} } ) }
Risposta
{ "data": { "mostPopular": [ { "popularity": 9 } ], "leastPopular": [ { "popularity": 1 } ] } }
Utilizzare i filtri delle query
Le query Data Connect vengono mappate a tutti i filtri e gli ordini SQL comuni.
Filtrare con where
con operatori orderBy
Restituisce tutte le righe corrispondenti della tabella (e le associazioni nidificate). Restituisce un array vuoto se nessun record corrisponde al filtro.
Query
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 } }
Risposta
{ "data": { "mostPopular": [ { "id": "some-uuid", "title": "Example Movie Title", "genre": "Action", "description": "A great movie" } ] } }
Filtrare in base al test per i valori nulli
Puoi testare i valori null
utilizzando l'operatore isNull
.
Query
query ListMoviesWithoutDescription { movies(where: { description: { isNull: true }}) { id title } }
Risposta
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" }, { "id": "another-uuid", "title": "Another Movie Title" } ] } }
Per altri operatori, consulta la guida di riferimento sui tipi di oggetti di input.
Filtrare con i confronti di valori
Puoi utilizzare operatori come lt
(minore di) e ge
(maggiore o uguale) per confrontare i valori nelle query.
Query
query ListMoviesByRating($minRating: Int!, $maxRating: Int!) { movies(where: { rating: { ge: $minRating, lt: $maxRating }}) { id title } }
Risposta
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" }, { "id": "another-uuid", "title": "Another Movie Title" } ] } }
Filtrare con gli operatori includes
e excludes
per i campi array
Puoi verificare che un campo array includa un elemento specificato.
L'esempio seguente illustra l'operatore includes
.
Data Connect supporta includesAll
, excludes
, excludesAll
e
altro ancora. Esamina tutti questi operatori per numeri interi, stringhe, date e altri tipi di dati nelle intestazioni _ListFilter
della documentazione di riferimento.
Query
query ListMoviesByTag($tag: String!) { movies(where: { tags: { includes: $tag }}) { # graphql: list the fields from the results to return id title } }
Risposta
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" } ] } }
Filtrare con operazioni sulle stringhe ed espressioni regolari
Le query possono utilizzare le tipiche operazioni di ricerca e confronto di stringhe, incluse le espressioni regolari. Nota: per efficienza, qui stai raggruppando diverse operazioni e le stai disambiguando con alias.
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}}) {...}
}
Filtra con la logica degli operatori _or
, _and
, _not
Utilizza _or
per una logica più complessa. Data Connect supporta anche gli operatori _and
e _not
.
Query
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 } }
Risposta
{ "data": { "movies": [ { "title": "Movie Title 1" }, { "title": "Movie Title 2" } ] } }
Scrivere query relazionali
Le query Data Connect possono accedere ai dati in base alle relazioni tra le tabelle. Puoi utilizzare le relazioni oggetto (uno-a-uno) o array (uno-a-molti) definite nello schema per eseguire query nidificate, ovvero recuperare i dati per un tipo insieme ai dati di un tipo nidificato o correlato.
Queste query utilizzano la sintassi magica Data Connect _on_
e _via
nei
campi di lettura generati.
Ricordati di esaminare lo schema di esempio.
Many-to-one
Ora esaminiamo una query per illustrare la sintassi di _on_
.
Query
query MyReviews @auth(level: USER) { user(key: {id_expr: "auth.uid"}) { reviews: reviews_on_user { movie { name } rating } } }
Risposta
{ "data": { "user": { "reviews": [ { "movie": { "name": "Movie Title" }, "rating": 5 } ] } } }
One to one
Puoi scrivere una query one-to-one utilizzando la sintassi _on_
.
Query
query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { movieMetadatas_on_movie { director } } }
Risposta
{ "data": { "movie": { "movieMetadatas_on_movie": { "director": "Some Director" } } } }
Many-to-many
Le query molti-a-molti utilizzano la sintassi _via_
. Una query molti-a-molti potrebbe
recuperare gli attori di un film specifico.
Query
query MoviesActors($id: UUID!) @auth(level: USER) { movie(id: $id) { actors: actors_via_MovieActors { name } } }
Risposta
{ "data": { "movie": { "actors": [ { "name": "Actor Name" } ] } } }
Ma possiamo scrivere una query più complessa, utilizzando gli alias, per filtrare in base a role
per recuperare gli attori e i film associati in mainActors
e
supportingActors
risultati. Poiché si tratta di una relazione molti-a-molti, viene utilizzata la sintassi _via_
.
Query
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 } } }
Risposta
{ "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" } ] } } }
Query di aggregazione
Che cosa sono gli aggregati e perché utilizzarli?
I campi aggregati ti consentono di eseguire calcoli su un elenco di risultati. Con i campi aggregati puoi:
- Trovare il punteggio medio di una recensione
- Trovare il costo totale degli articoli in un carrello degli acquisti
- Trovare il prodotto con la valutazione più alta o più bassa
- Contare il numero di prodotti nel tuo negozio
Gli aggregati vengono eseguiti sul server, il che offre una serie di vantaggi rispetto al calcolo lato client:
- Prestazioni più rapide dell'app (in quanto eviti i calcoli lato client)
- Costi di uscita dei dati ridotti (in quanto invii solo i risultati aggregati anziché tutti gli input)
- Maggiore sicurezza (poiché puoi concedere ai clienti l'accesso ai dati aggregati anziché all'intero set di dati)
Schema di esempio per i dati aggregati
In questa sezione passeremo a uno schema di esempio di un negozio, che è un buon punto di partenza per spiegare come utilizzare gli aggregati:
type Product @table {
name: String!
manufacturer: String!
quantityInStock: Int!
price: Float!
expirationDate: Date
}
Aggregati semplici
_count per tutti i campi
Il campo aggregato più semplice è _count
: restituisce il numero di righe che corrispondono alla tua
query. Per ogni campo del tipo, Data Connect
genera i campi aggregati corrispondenti a seconda del tipo di campo.
Query
query CountProducts {
products {
_count
}
}
Risposta one
one
Ad esempio, se nel tuo database hai 5 prodotti, il risultato sarà:
{
"products": [
{
"_count": 5
}
]
}
Tutti i campi hanno un campo <field>_count
, che conta il numero di righe con un
valore non nullo in quel campo.
Query
query CountProductsWithExpirationDate {
products {
expirationDate_count
}
}
Rispostafield_count
field_count
Ad esempio, se hai 3 prodotti con una data di scadenza, il risultato sarà:
{
"products": [
{
"expirationDate_count": 3
}
]
}
_min, _max, _sum e _avg per i campi numerici
I campi numerici (int, float, int64) hanno anche <field>_min
, <field>_max
,
<field>_sum
e <field>_avg
.
Query
query NumericAggregates {
products {
quantityInStock_max
price_min
price_avg
quantityInStock_sum
}
}
Risposta_min _max _sum _avg
_min _max _sum _avg
Ad esempio, se hai i seguenti prodotti:
- Prodotto A:
quantityInStock: 10
,price: 2.99
- Prodotto B:
quantityInStock: 5
,price: 5.99
- Prodotto C:
quantityInStock: 20
,price: 1.99
Il risultato sarebbe:
{
"products": [
{
"quantityInStock_max": 20,
"price_min": 1.99,
"price_avg": 3.6566666666666666,
"quantityInStock_sum": 35
}
]
}
_min e _max per date e timestamp
I campi data e ora hanno <field>_min
e <field>_max
.
Query
query DateAndTimeAggregates {
products {
expirationDate_max
expirationDate_min
}
}
Risposta_min _maxdatetime
_min _maxdatetime
Ad esempio, se hai le seguenti date di scadenza:
- Prodotto A:
2024-01-01
- Prodotto B:
2024-03-01
- Prodotto C:
2024-02-01
Il risultato sarebbe:
{
"products": [
{
"expirationDate_max": "2024-03-01",
"expirationDate_min": "2024-01-01"
}
]
}
Distinct
L'argomento distinct
ti consente di ottenere tutti i valori univoci per un campo
(o una combinazione di campi). Ad esempio:
Query
query ListDistinctManufacturers {
products(distinct: true) {
manufacturer
}
}
Rispostadistinct
distinct
Ad esempio, se hai i seguenti produttori:
- Prodotto A:
manufacturer: "Acme"
- Prodotto B:
manufacturer: "Beta"
- Prodotto C:
manufacturer: "Acme"
Il risultato sarebbe:
{
"products": [
{ "manufacturer": "Acme" },
{ "manufacturer": "Beta" }
]
}
Puoi anche utilizzare l'argomento distinct
nei campi aggregati per aggregare invece i valori distinti. Ad esempio:
Query
query CountDistinctManufacturers {
products {
manufacturer_count(distinct: true)
}
}
Rispostadistinctonaggregate
distinctonaggregate
Ad esempio, se hai i seguenti produttori:
- Prodotto A:
manufacturer: "Acme"
- Prodotto B:
manufacturer: "Beta"
- Prodotto C:
manufacturer: "Acme"
Il risultato sarebbe:
{
"products": [
{
"manufacturer_count": 2
}
]
}
Aggregati raggruppati
Esegui un'aggregazione raggruppata selezionando un mix di campi aggregati e non aggregati in un tipo. In questo modo vengono raggruppate tutte le righe corrispondenti che hanno lo stesso valore per i campi non aggregati e vengono calcolati i campi aggregati per quel gruppo. Ad esempio:
Query
query MostExpensiveProductByManufacturer {
products {
manufacturer
price_max
}
}
Rispostagroupedaggregates
groupedaggregates
Ad esempio, se hai i seguenti prodotti:
- Prodotto A:
manufacturer: "Acme"
,price: 2.99
- Prodotto B:
manufacturer: "Beta"
,price: 5.99
- Prodotto C:
manufacturer: "Acme"
,price: 1.99
Il risultato sarebbe:
{
"products": [
{ "manufacturer": "Acme", "price_max": 2.99 },
{ "manufacturer": "Beta", "price_max": 5.99 }
]
}
having
e where
con aggregazioni raggruppate
Puoi anche utilizzare gli argomenti having
e where
per restituire solo i gruppi che
soddisfano un criterio fornito.
having
ti consente di filtrare i gruppi in base ai campi aggregatiwhere
consente di filtrare le righe in base a campi non aggregati.
Query
query FilteredMostExpensiveProductByManufacturer {
products(having: {price_max: {ge: 2.99}}) {
manufacturer
price_max
}
}
Rispostahavingwhere
havingwhere
Ad esempio, se hai i seguenti prodotti:
- Prodotto A:
manufacturer: "Acme"
,price: 2.99
- Prodotto B:
manufacturer: "Beta"
,price: 5.99
- Prodotto C:
manufacturer: "Acme"
,price: 1.99
Il risultato sarebbe:
{
"products": [
{ "manufacturer": "Acme", "price_max": 2.99 },
{ "manufacturer": "Beta", "price_max": 5.99 }
]
}
Aggregazioni tra tabelle
I campi aggregati possono essere utilizzati in combinazione con i campi della relazione uno-a-molti generata
per rispondere a domande complesse sui tuoi dati. Di seguito è riportato uno schema modificato, con una tabella separata, Manufacturer
, che possiamo utilizzare negli esempi:
type Product @table {
name: String!
manufacturer: Manufacturer!
quantityInStock: Int!
price: Float!
expirationDate: Date
}
type Manufacturer @table {
name: String!
headquartersCountry: String!
}
Ora possiamo utilizzare i campi aggregati per trovare, ad esempio, il numero di prodotti realizzati da un produttore:
Query
query GetProductCount($id: UUID) {
manufacturers {
name
products_on_manufacturer {
_count
}
}
}
Risposta aggregatesacrosstables
aggregatesacrosstables
Ad esempio, se hai i seguenti produttori:
- Produttore A:
name: "Acme"
,products_on_manufacturer: 2
- Produttore B:
name: "Beta"
,products_on_manufacturer: 1
Il risultato sarebbe:
{
"manufacturers": [
{ "name": "Acme", "products_on_manufacturer": { "_count": 2 } },
{ "name": "Beta", "products_on_manufacturer": { "_count": 1 } }
]
}
Scrivere query avanzate: utilizza i campi query
per leggere i dati in operazioni in più passaggi
Esistono molte situazioni in cui potresti voler leggere il database durante l'esecuzione di una mutazione per cercare e verificare i dati esistenti prima di eseguire, ad esempio, inserimenti o aggiornamenti. Queste opzioni consentono di risparmiare operazioni di andata e ritorno e quindi costi.
Data Connect supporta questa funzionalità. Consulta le operazioni in più passaggi.
Passaggi successivi
Potrebbe interessarti:
- Generare query per le tue app utilizzando gli strumenti di assistenza AI
- Autorizzazione delle query in base alla guida all'autorizzazione
- Chiamare le query dal codice client per web, iOS, Android e Flutter.