Firebase Data Connect te permite crear conectores para tus instancias de PostgreSQL administradas con Google Cloud SQL. Estos conectores son combinaciones de consultas y mutaciones para usar tus datos desde tu esquema.
En la guía de inicio, se presentó un esquema de app de revisión de películas para PostgreSQL.
En esa guía, también se presentaron operaciones administrativas ad hoc y que se pueden implementar, incluidas las consultas.
- Las búsquedas implementables son aquellas que implementas para llamar desde apps cliente, con los extremos de API que defines. Los empaquetas en un conector implementado en el servidor. Las herramientas de Data Connect generan SDKs cliente basados en tu API. Las políticas de IAM no protegen las consultas implementadas, por lo que debes asegurarte de protegerlas con la directiva Data Connect
@auth
. - Las consultas administrativas ad hoc se ejecutan desde entornos con privilegios para leer datos. Puedes crearlas y ejecutarlas en la consola de Firebase o en entornos de desarrollo locales con nuestra extensión de Data Connect para VS Code.
En esta guía, se analizan con mayor detalle las consultas implementables.
Características de las búsquedas de Data Connect
Data Connect te permite realizar consultas básicas de todas las formas que esperarías dada una base de datos de PostgreSQL.
Sin embargo, con las extensiones de Data Connect para GraphQL, puedes implementar consultas avanzadas para crear apps más rápidas y eficientes:
- Usa escalares de clave que muestran muchas operaciones para simplificar las operaciones repetidas en los registros.
- Realiza consultas en el transcurso de operaciones de mutación de varios pasos para buscar datos, lo que permite ahorrar líneas de código y viajes de ida y vuelta al servidor.
Usa campos generados para crear consultas
Tus operaciones de Data Connect extenderán un conjunto de campos Data Connect generados automáticamente según los tipos y las relaciones de tipos en tu esquema. Estos campos se generan con herramientas locales cada vez que editas tu esquema.
Puedes usar los campos generados para implementar consultas cada vez más complejas, desde recuperar registros individuales o varios registros de tablas únicas hasta varios registros de tablas relacionadas.Supongamos que tu esquema contiene un tipo Movie
y un tipo Actor
asociado.
Data Connect genera los campos movie
, movies
y actors_on_movies
, entre otros.
Consulta con el campo
movie
El campo |
Usa este campo para consultar una sola película por su clave. query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } } |
Consulta con el campo
movies
El campo |
Usa este campo para consultar varias películas, por ejemplo, todas las películas de un año determinado. query GetMovies($myYear: Int!) { movies(where: { year: { eq: $myYear } }) { title } } |
Consulta con el campo
actors_on_movies
El campo |
Usa este campo para consultar todos los actores asociados con una película determinada. query GetActorsOnMovie($myKey: Movie_Key!) { actors_on_movies(where: { movie: { key: { eq: $myKey } } }) { actor { name } } } |
Elementos esenciales de una búsqueda
Las consultas de Data Connect son consultas de GraphQL con extensiones de Data Connect. Al igual que con una consulta de GraphQL normal, puedes definir un nombre de operación y una lista de variables de GraphQL.
Data Connect extiende las consultas de GraphQL con directivas personalizadas, como @auth
.
Por lo tanto, la siguiente búsqueda tiene lo siguiente:
- Una definición de tipo
query
- Nombre de una operación
ListMoviesByGenre
(consulta) - Un solo argumento de consulta, aquí una variable
$genre
de tipoString
- Una sola directiva,
@auth
. - Un solo campo,
movies
.
query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
movies(where: { genre: { eq: $genre } }) {
id
title
}
}
Cada argumento de consulta requiere una declaración de tipo, un tipo integrado como String
o un tipo personalizado definido por el esquema como Movie
.
En esta guía, se analizará la firma de consultas cada vez más complejas. Terminarás con la presentación de expresiones de relación potentes y concisas que puedes usar para crear tus consultas implementables.
Escalares clave en las búsquedas
Pero primero, una nota sobre los escalares clave.
Data Connect define un escalar de clave especial para representar las claves primarias de cada tabla, identificadas por {TableType}_Key. Es un objeto JSON de valores de clave principal.
Recuperas los valores escalares clave como una respuesta que devuelven la mayoría de los campos de lectura generados automáticamente o, por supuesto, de las búsquedas en las que recuperaste todos los campos necesarios para compilar la clave escalar.
Las consultas automáticas singulares, como movie
en nuestro ejemplo en ejecución, admiten un argumento de clave que acepta un escalar de clave.
Puedes pasar un escalar de clave como literal. Sin embargo, puedes definir variables para pasar los escalares clave como entrada.
Consulta
query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } }
Respuesta
{ "data": { "movie": { "title": "Example Movie Title" } } }
Estos se pueden proporcionar en el JSON de la solicitud de la siguiente manera (o en otros formatos de serialización):
{
# …
"variables": {
"myKey": {"id": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"}
}
}
Gracias al análisis personalizado de escalares, también se puede construir un Movie_Key
con la sintaxis de objetos, que puede contener variables. Esto es más útil cuando deseas dividir componentes individuales en diferentes variables por algún motivo.
Escribe consultas básicas
Puedes comenzar a escribir consultas para obtener registros individuales de tu base de datos o enumerar registros de una tabla con la opción de limitar y ordenar los resultados.
Recupera registros individuales
La consulta más simple obtiene un solo registro por ID. Tu consulta usará el campo movie
generado automáticamente.
Consulta
query GetMovieById($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { id title imageUrl genre } }
Respuesta
{ "data": { "movie": { "id": "some-uuid", "title": "Example Movie Title", "imageUrl": "https://example.com/movie.jpg", "genre": "Action" } } }
Recupera todos los registros de una tabla
Para recuperar un subconjunto de campos de la lista completa de películas de la tabla Movies
, tu consulta usará el campo movies
generado automáticamente, y tu implementación podría verse de la siguiente manera.
Consulta
query ListMovies @auth(level: PUBLIC) { movies { id title imageUrl genre } }
Respuesta
{ "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" } ] } }
Usa los operadores orderBy
, limit
y offset
Naturalmente, enumerar todos los registros de una tabla tiene una utilidad limitada.
Puedes ordenar y paginar los resultados. Estos argumentos se aceptan, pero no se muestran en los resultados.
Aquí, la consulta obtiene los títulos de las 10 películas mejor calificadas.
Consulta
query MoviesTop10 { movies(orderBy: [{ rating: DESC }], limit: 10) { # graphql: list the fields from the results to return title } }
Respuesta
{ "data": { "movies": [ { "title": "Top Movie 1" }, { "title": "Top Movie 2" }, { "title": "Top Movie 3" } // ... other 7 movies ] } }
Es posible que tengas un caso de uso para recuperar filas a partir de un desplazamiento, como las películas del 11 al 20 ordenadas por calificación.
Consulta
query Movies11to20 { movies(orderBy: [{ rating: DESC }], limit: 10, offset: 10) { # graphql: list the fields from the results to return title } }
Respuesta
{ "data": { "movies": [ { "title": "Movie 11" }, { "title": "Movie 12" }, { "title": "Movie 13" } // ... other 7 movies ] } }
Usa alias en las consultas
Data Connect admite alias de GraphQL en las consultas. Con los alias, puedes cambiar el nombre de los datos que se muestran en los resultados de una consulta. Una sola consulta de Data Connect puede aplicar varios filtros o realizar otras operaciones de consulta en una solicitud eficiente al servidor, lo que equivale a emitir varias "subconsultas" a la vez. Para evitar colisiones de nombres en el conjunto de datos devuelto, usa alias para distinguir las subconsultas.
Esta es una consulta en la que una expresión usa los alias mostPopular
y leastPopular
.
Consulta
query ReviewPopularitySpread($genre: String) { mostPopular: review( first: { where: {genre: {eq: $genre}}, orderBy: {popularity: DESC} } ), leastPopular: review( last: { where: {genre: {eq: $genre}}, orderBy: {popularity: DESC} } ) }
Respuesta
{ "data": { "mostPopular": [ { "popularity": 9 } ], "leastPopular": [ { "popularity": 1 } ] } }
Usa filtros de consultas
Las consultas de Data Connect se asignan a todos los filtros y operaciones de orden comunes de SQL.
Filtra con where
y operadores orderBy
Devuelve todas las filas coincidentes de la tabla (y las asociaciones anidadas). Muestra un array vacío si no hay registros que coincidan con el filtro.
Consulta
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 } }
Respuesta
{ "data": { "mostPopular": [ { "id": "some-uuid", "title": "Example Movie Title", "genre": "Action", "description": "A great movie" } ] } }
Filtrar por pruebas de valores nulos
Puedes probar los valores de null
con el operador isNull
.
Consulta
query ListMoviesWithoutDescription { movies(where: { description: { isNull: true }}) { id title } }
Respuesta
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" }, { "id": "another-uuid", "title": "Another Movie Title" } ] } }
Para obtener más operadores, consulta la guía de referencia de tipos de objetos de entrada.
Filtra con comparaciones de valores
Puedes usar operadores como lt
(menor que) y ge
(mayor que o igual) para comparar valores en tus consultas.
Consulta
query ListMoviesByRating($minRating: Int!, $maxRating: Int!) { movies(where: { rating: { ge: $minRating, lt: $maxRating }}) { id title } }
Respuesta
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" }, { "id": "another-uuid", "title": "Another Movie Title" } ] } }
Filtra con los operadores includes
y excludes
para los campos de array
Puedes probar que un campo de array incluya un elemento especificado.
En el siguiente ejemplo, se ilustra el operador includes
.
Data Connect admite includesAll
, excludes
, excludesAll
y mucho más. Revisa todos los operadores de números enteros, cadenas, fechas y otros tipos de datos en los encabezados de _ListFilter
de la documentación de referencia.
Consulta
query ListMoviesByTag($tag: String!) { movies(where: { tags: { includes: $tag }}) { # graphql: list the fields from the results to return id title } }
Respuesta
{ "data": { "movies": [ { "id": "some-uuid", "title": "Example Movie Title" } ] } }
Filtrar con operaciones de cadenas y expresiones regulares
Tus consultas pueden usar operaciones típicas de búsqueda y comparación de cadenas, incluidas las expresiones regulares. Ten en cuenta que, para mayor eficiencia, aquí se agrupan varias operaciones y se desambiguan 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}}) {...}
}
Filtrar con la lógica de los operadores _or
, _and
y _not
Usa _or
para una lógica más compleja. Data Connect también admite los operadores _and
y _not
.
Consulta
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 } }
Respuesta
{ "data": { "movies": [ { "title": "Movie Title 1" }, { "title": "Movie Title 2" } ] } }
Escribe consultas relacionales
Las consultas de Data Connect pueden acceder a los datos según las relaciones entre las tablas. Puedes usar las relaciones de objeto (uno a uno) o de array (uno a varios) definidas en tu esquema para realizar consultas anidadas, es decir, recuperar datos de un tipo junto con datos de un tipo anidado o relacionado.
Estas consultas usan la sintaxis mágica Data Connect _on_
y _via
en los campos de lectura generados.
Recuerda revisar el esquema de ejemplo.
De muchos a uno
Ahora, veamos una consulta para ilustrar la sintaxis de _on_
.
Consulta
query MyReviews @auth(level: USER) { user(key: {id_expr: "auth.uid"}) { reviews: reviews_on_user { movie { name } rating } } }
Respuesta
{ "data": { "user": { "reviews": [ { "movie": { "name": "Movie Title" }, "rating": 5 } ] } } }
Uno a uno
Puedes escribir una consulta de uno a uno con la sintaxis de _on_
.
Consulta
query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { movieMetadatas_on_movie { director } } }
Respuesta
{ "data": { "movie": { "movieMetadatas_on_movie": { "director": "Some Director" } } } }
De muchos a muchos
Las consultas de muchos a muchos usan la sintaxis de _via_
. Una consulta de muchos a muchos podría recuperar actores para una película específica.
Consulta
query MoviesActors($id: UUID!) @auth(level: USER) { movie(id: $id) { actors: actors_via_MovieActors { name } } }
Respuesta
{ "data": { "movie": { "actors": [ { "name": "Actor Name" } ] } } }
Sin embargo, podemos escribir una consulta más compleja, usando alias, para filtrar según role
y recuperar actores y películas asociadas en los resultados de mainActors
y supportingActors
. Dado que se trata de una relación de muchos a muchos, se usa la sintaxis de _via_
.
Consulta
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 } } }
Respuesta
{ "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" } ] } } }
Consultas de agregación
¿Qué son los agregados y por qué usarlos?
Los campos de agregación te permiten realizar cálculos en una lista de resultados. Con los campos de agregación, puedes hacer lo siguiente:
- Cómo encontrar la puntuación promedio de una opinión
- Cómo encontrar el costo total de los artículos en un carrito de compras
- Cómo encontrar el producto con la calificación más alta o más baja
- Cuenta la cantidad de productos que hay en tu tienda
Los agregados se realizan en el servidor, lo que ofrece varios beneficios en comparación con el cálculo del lado del cliente:
- Rendimiento más rápido de la app (ya que evitas los cálculos del cliente)
- Se reducen los costos de salida de datos (ya que solo envías los resultados agregados en lugar de todas las entradas).
- Seguridad mejorada (ya que puedes darles a los clientes acceso a datos agregados en lugar de a todo el conjunto de datos)
Ejemplo de esquema para agregados
En esta sección, cambiaremos a un esquema de ejemplo de tienda, que es útil para explicar cómo usar los agregados:
type Product @table {
name: String!
manufacturer: String!
quantityInStock: Int!
price: Float!
expirationDate: Date
}
Agregados simples
_count para todos los campos
El campo agregado más simple es _count
, que devuelve la cantidad de filas que coinciden con tu búsqueda. Para cada campo de tu tipo, Data Connect genera los campos agregados correspondientes según el tipo de campo.
Consulta
query CountProducts {
products {
_count
}
}
Respuesta one
one
Por ejemplo, si tienes 5 productos en tu base de datos, el resultado sería el siguiente:
{
"products": [
{
"_count": 5
}
]
}
Todos los campos tienen un campo <field>_count
, que cuenta cuántas filas tienen un valor no nulo en ese campo.
Consulta
query CountProductsWithExpirationDate {
products {
expirationDate_count
}
}
Respuestafield_count
field_count
Por ejemplo, si tienes 3 productos con fecha de vencimiento, el resultado sería el siguiente:
{
"products": [
{
"expirationDate_count": 3
}
]
}
_min, _max, _sum y _avg para los campos numéricos
Los campos numéricos (int, float, int64) también tienen <field>_min
, <field>_max
, <field>_sum
y <field>_avg
.
Consulta
query NumericAggregates {
products {
quantityInStock_max
price_min
price_avg
quantityInStock_sum
}
}
Respuesta_min _max _sum _avg
_min _max _sum _avg
Por ejemplo, si tienes los siguientes productos:
- Producto A:
quantityInStock: 10
,price: 2.99
- Producto B:
quantityInStock: 5
,price: 5.99
- Producto C:
quantityInStock: 20
,price: 1.99
El resultado sería el siguiente:
{
"products": [
{
"quantityInStock_max": 20,
"price_min": 1.99,
"price_avg": 3.6566666666666666,
"quantityInStock_sum": 35
}
]
}
_min y _max para fechas y marcas de tiempo
Los campos de fecha y marca de tiempo tienen <field>_min
y <field>_max
.
Consulta
query DateAndTimeAggregates {
products {
expirationDate_max
expirationDate_min
}
}
Respuesta_min _maxdatetime
_min _maxdatetime
Por ejemplo, si tienes las siguientes fechas de vencimiento:
- Producto A:
2024-01-01
- Producto B:
2024-03-01
- Producto C:
2024-02-01
El resultado sería el siguiente:
{
"products": [
{
"expirationDate_max": "2024-03-01",
"expirationDate_min": "2024-01-01"
}
]
}
Distinto
El argumento distinct
te permite obtener todos los valores únicos de un campo (o una combinación de campos). Por ejemplo:
Consulta
query ListDistinctManufacturers {
products(distinct: true) {
manufacturer
}
}
Respuestadistinct
distinct
Por ejemplo, si tienes los siguientes fabricantes:
- Producto A:
manufacturer: "Acme"
- Producto B:
manufacturer: "Beta"
- Producto C:
manufacturer: "Acme"
El resultado sería el siguiente:
{
"products": [
{ "manufacturer": "Acme" },
{ "manufacturer": "Beta" }
]
}
También puedes usar el argumento distinct
en los campos de agregación para agregar los valores distintos. Por ejemplo:
Consulta
query CountDistinctManufacturers {
products {
manufacturer_count(distinct: true)
}
}
Respuestadistinctonaggregate
distinctonaggregate
Por ejemplo, si tienes los siguientes fabricantes:
- Producto A:
manufacturer: "Acme"
- Producto B:
manufacturer: "Beta"
- Producto C:
manufacturer: "Acme"
El resultado sería el siguiente:
{
"products": [
{
"manufacturer_count": 2
}
]
}
Agregados agrupados
Para realizar un agregado agrupado, selecciona una combinación de campos agregados y no agregados en un tipo. Esto agrupa todas las filas coincidentes que tienen el mismo valor para los campos no agregados y calcula los campos agregados para ese grupo. Por ejemplo:
Consulta
query MostExpensiveProductByManufacturer {
products {
manufacturer
price_max
}
}
Respuestagroupedaggregates
groupedaggregates
Por ejemplo, si tienes los siguientes productos:
- Producto A:
manufacturer: "Acme"
,price: 2.99
- Producto B:
manufacturer: "Beta"
,price: 5.99
- Producto C:
manufacturer: "Acme"
,price: 1.99
El resultado sería el siguiente:
{
"products": [
{ "manufacturer": "Acme", "price_max": 2.99 },
{ "manufacturer": "Beta", "price_max": 5.99 }
]
}
having
y where
con agregados agrupados
También puedes usar los argumentos having
y where
para devolver solo los grupos que cumplen con un criterio proporcionado.
having
te permite filtrar grupos por sus campos agregadoswhere
te permite filtrar las filas según campos no agregados.
Consulta
query FilteredMostExpensiveProductByManufacturer {
products(having: {price_max: {ge: 2.99}}) {
manufacturer
price_max
}
}
Respuestahavingwhere
havingwhere
Por ejemplo, si tienes los siguientes productos:
- Producto A:
manufacturer: "Acme"
,price: 2.99
- Producto B:
manufacturer: "Beta"
,price: 5.99
- Producto C:
manufacturer: "Acme"
,price: 1.99
El resultado sería el siguiente:
{
"products": [
{ "manufacturer": "Acme", "price_max": 2.99 },
{ "manufacturer": "Beta", "price_max": 5.99 }
]
}
Agregaciones en varias tablas
Los campos de agregación se pueden usar en conjunto con los campos de relación de uno a varios generados para responder preguntas complejas sobre tus datos. A continuación, se muestra un esquema modificado, con una tabla separada, Manufacturer
, que podemos usar en los ejemplos:
type Product @table {
name: String!
manufacturer: Manufacturer!
quantityInStock: Int!
price: Float!
expirationDate: Date
}
type Manufacturer @table {
name: String!
headquartersCountry: String!
}
Ahora podemos usar campos agregados para realizar acciones como averiguar cuántos productos fabrica una empresa:
Consulta
query GetProductCount($id: UUID) {
manufacturers {
name
products_on_manufacturer {
_count
}
}
}
Respuesta aggregatesacrosstables
aggregatesacrosstables
Por ejemplo, si tienes los siguientes fabricantes:
- Fabricante A:
name: "Acme"
,products_on_manufacturer: 2
- Fabricante B:
name: "Beta"
,products_on_manufacturer: 1
El resultado sería el siguiente:
{
"manufacturers": [
{ "name": "Acme", "products_on_manufacturer": { "_count": 2 } },
{ "name": "Beta", "products_on_manufacturer": { "_count": 1 } }
]
}
Escribe consultas avanzadas: Usa campos query
para leer datos en operaciones de varios pasos
Hay muchas situaciones en las que es posible que desees leer tu base de datos durante la ejecución de una mutación para buscar y verificar los datos existentes antes de realizar, por ejemplo, inserciones o actualizaciones. Estas opciones ahorran operaciones de ida y vuelta y, por lo tanto, costos.
Data Connect admite esta funcionalidad. Consulta operaciones de varios pasos.
Próximos pasos
También te puede interesar:
- Genera consultas para tus apps con herramientas de asistencia de IA
- Autoriza tus búsquedas según la guía de autorización
- Llamar a consultas desde el código del cliente para la Web, iOS, Android y Flutter