Consultas SQL no Firebase
Entre os recursos que a plataforma de serviços Firebase disponibiliza está o Cloud Firestore. Trata-se de um banco de dados NoSQL hospedado nas nuvens onde armazenamos os dados em documentos.
A consulta de dados deste banco é eficiente é flexível, mas há diferenças se você já desenvolve com SQL.
Nesse artigo apresento o FireSql. Uma biblioteca criada com base no SDK oficial do Firebase que permite
consultar coleções no Cloud Firestore usando a sintaxe SQL.
Vamos criar três coleções e alguns documentos para criar consultas sql. Um projeto em Angular 7 foi criado e as funções de exemplos estão todas no componente principal.
No final do artigo colocarei o link do projeto no Github.
Criando as Coleções. Acessando o console do firebase com suas credenciais google e crie um projeto. Para mais detalhes, veja meu artigo.
Vamos criar as coleções para executar as consultas.
Criei 3 coleções nomeando como cidades, estados e pessoas.
Para estados eu criei alguns documentos com os campos nome e sigla.
Para cidades foram 3 campos, nome, uf como string e populacao (sem ~ ç) como number. Também criei alguns documentos.
Finalmente para a coleção pessoas, desenvolvi os seguintes campos:
Indiquei o nome como string, idade como number, tags como array e um map endereco com os campos bairro, numero e rua. Assim como as coleções anteriores, também criei mais documentos para a realização das consultas.
Finalizado a inclusão de valores, o próximo passo é instalar a biblioteca.
Após criar um projeto com o Angular CLI, no terminal do projeto vamos informar:
npm install firesql firebase
Assim adicionamos as bibliotecas do Firebase e o FireSql.
No componente principal, vamos iniciar realizando os seguintes imports:
import { Component, OnInit } from ‘@angular/core’;import { FireSQL } from ‘firesql’;import * as firebase from ‘firebase/app’;import ‘firebase/firestore’;
Dessa forma podemos declarar os objetos necessários para a realização das consultas.
Na sequência podemos declarar um objeto que realizará as consultas, definindo também as configurações para conectar no firebase:
fireSQL;constructor() {let firebaseConfig = { apiKey: '<your-api-key>',
authDomain: '<your-auth-domain>',
databaseURL: '<your-database-url>',
storageBucket: '<your-storage-bucket>',
messagingSenderId: 'seus-dados',
appId: 'seus-dados'
};firebase.initializeApp(firebaseConfig);this.fireSQL = new FireSQL(firebase.firestore());}
No método construtor definimos as configurações do projeto obtidas na página do projeto no Firebase, inicializando o app e instanciando o objeto fireSQL.
A partir deste momento já podemos escrever as consultas.
Vamos começar testando operador WHERE na coleção cidades. O objetivo é apresentar todos os documentos que tem a uf do paraná e a população superior a dez mil.
A função ficou assim:
consultaComWhere() {const cidades = this.fireSQL.query(`SELECT nome as cidade, uf, populacaoFROM cidadesWhere uf = 'PR' and populacao > 10000`);cidades.then(lista => {for (let cidade of lista) {console.log(`${cidade.cidade} - UF: ${cidade.uf} - População: ${cidade.populacao}`)}})}
Utilizamos a sintaxe clássica do SQL utilizando SELEC FROM e ainda usamos um alias para o campo nome.
O método query retorna uma promise pelo qual podemos recuperar no callback o array do resultado.
Realizamos um loop para exibir no console as propriedades cidade, uf e populacao.
Para testar, chamamos a função no método ngOnInit().
ngOnInit(): void {this.consultaComWhere()}
O resultado no console:
Podemos utilizar o operador LIKE para campos do tipo string, usando o curinga %.
consultaComLike() {const estados = this.fireSQL.query(`SELECT * FROM estadosWHERE nome LIKE 'P%'`);estados.then(lista => {for (let uf of lista) {console.log(`${uf.nome} - UF: ${uf.sigla} `)}})}
No console a relação de todos os estados iniciados com a letra P
Podemos definir um conjunto de valores no parâmetro utilizando o IN:
consultaComIN() {const cidades = this.fireSQL.query(`SELECT nome as cidade, uf, populacaoFROM cidadesWHERE uf IN ('PR', 'SP')`);cidades.then(lista => {for (let cidade of lista) {console.log(`${cidade.cidade} - UF: ${cidade.uf} - População: ${cidade.populacao}`)}})}
E o resultado:
Cidades de São Paulo e do Paraná.
Uma forma comum de modelar em NoSQL é a utilização de objetos aninhados. Utilizamos essa abordagem na propriedade endereco da pessoa. Para fazer consultas devemos usar as propriedades entre acentos graves:
consultaComObjetoAninhado() {const pessoas = this.fireSQL.query(`SELECT nome, endereco FROM pessoasWHERE \`endereco.bairro\` = 'Centro'`);pessoas.then(lista => {console.log(lista)for (let pessoa of lista) {console.log(`${pessoa.nome} - Endereco: ${pessoa.endereco.rua} Bairro: ${pessoa.endereco.bairro} `)}})}
Definimos uma consulta que retorne todos os registros de pessoas do Centro. Observe que devemos usar as barras invertidas pois já estamos usando o ` no início da consulta.
Na próxima função vamos implementar verificando o conteúdo de um campo do tipo array. Usaremos o operador CONTAINS:
consultaArrays() {const pessoas = this.fireSQL.query(`SELECT nome, endereco, tags FROM pessoasWHERE tags CONTAINS 'saúde'`);pessoas.then(lista => {console.log(lista)for (let pessoa of lista) {console.log(`${pessoa.nome} - Interesses: ${JSON.stringify(pessoa.tags)}`)}})}
Resultado:
Verificamos no campo tags o valor saúde. Para exibir utilizamos a função JSON.stringify.
Podemos também realizar cálculos como média, mínimo e máximo dos valores. A função seguinte apresenta a implementação:
consultaEstatistica() {const estatistica = this.fireSQL.query(`SELECT MIN(idade) as minimo, AVG(idade) as media, MAX(idade) as maximoFROM pessoas`);estatistica.then(lista => {console.log(lista)for (let estatistica of lista) {console.log(`Mínimo: ${estatistica.minimo} - Máximo: ${estatistica.maximo} - Média: ${estatistica.media}`)}})}
O console ficou:
Infelizmente a biblioteca ainda tem algumas restrições e limites como:
- Somente SELECT por enquanto. Há previsão para implementações futuras par INSERT, UPDATE e DELETE;
- Não suporta JOINs nem negação NOT :(
- LIMIT não aceita OFFSET somente um número
- GROUP BY não pode ser utilizado com ORDER BY
De qualquer forma, é uma biblioteca muito interessante, pois é ajustada para criar uma quantidade mínima de consultas nos servidores do Firebase.
Fica a dica.
Links