Firebase Cloud Functions — Pesquisa de Texto na Base de dados

O artigo original pode ser encontrado no Medium.


Uma das funcionalidades mais requisitadas à equipe do Firebase é a possibilidade de fazer a clássica “Pesquisa de Texto” na Realtime Database ou no Cloud Firestore. Para quem vem do SQL, esta é a famosa operação LIKE, que é bastante utilizada em caixas/campos de procura de texto.

Na altura em que a Realtime Database era o único serviço de Base de Dados do Firebase, esta funcionalidade já era pedida por desenvolvedores e, como solução, o Firebase trouxe a Flashlight — uma biblioteca que conecta-se à plataforma ElasticSearch para permitir estas pesquisas.

Para quem não conhece, ElasticSearch é uma plataforma que faz a indexação de dados para futuras pesquisas. Ela funciona da seguinte forma: Você envia para a plataforma os dados que precisam ser indexados (neste caso, o nó da Realtime Database em que pretende pesquisar) e para fazer a pesquisa você envia uma requisição HTTP para a REST API deles e a API retorna os resultados da sua pesquisa.

Quando surgiu o Cloud Firestore, vimos várias funcionalidades de consulta(querying) de dados sendo adicionadas, que podemos dizer que são melhorias quando comparadas com as funcionalidades de consulta que existiam na Realtime Database. Mas infelizmente, ainda nada sobre a Pesquisa de Texto. Como solução, o Firebase criou um Tutorial de como conectar Firestore à Algolia para Pesquisa de Texto. Algolia é outra plataforma de indexação muito similar ao ElasticSearch, inclusive funcionam da mesma maneira.

Apesar destas plataformas parecerem ser a solução perfeita, existem alguns aspetos a ter em conta:

  1. Você está partilhando os seus dados com plataformas de terceiros;
  2. É recomendado fazer as requisições em um servidor, pois estas plataformas dão-lhe uma Chave (API KEY) que não deverá ser exposta em aplicações cliente.

Segundo o tutorial do Firebase, o 2º ponto que mencionei não será um problema, afinal de contas, existe o Firebase Cloud Functions que permite executar algumas funções no lado do servidor (server-side).

Apesar da combinação “Cloud Functions +Algolia/ElasticSearch” ser perfeita, ela tem um inconveniente: quando estiver a utilizar o plano grátis (Spark Plan) do Firebase, as Cloud Functions não podem enviar requisições para endereços externos (que não fazem parte da Google). Só quem estiver a utilizar um dos planos pagos (Flame ou Blaze Plan) é que tem a permissão para fazer isso.
Isto implica que caso você queira enviar requisições à Algolia/ElasticSearch através das Cloud Functions, você precisa adicionar o seu cartão de crédito e optar por um dos planos pagos.

Adicionar um cartão de crédito não deve ser problema para alguns, até porque mesmo depois de adicionar, eles não irão cobrar-lhe nada até que atinja um certo limite (conheça os limites na tabela de preços) e este limite é alto o suficiente para que uma aplicação de pequena escala não o atinja em pouco tempo.

Mas por outro lado, existem desenvolvedores que não pretendem utilizar estes planos, mesmo porque provavelmente não utilizarão nem metade das funcionalidades oferecidas ou porque estão a desenvolver apenas um protótipo. Foi a pensar nestes desenvolvedores que decidi criar uma forma de fazer a Pesquisa de Texto no plano grátis (Spark).

Tocha — Pesquisas de Texto no Plano Spark

Tocha é uma biblioteca Open Source, por mim desenvolvida, que permite fazer pesquisas de texto no Cloud Firestore e na Realtime Database mesmo que o seu projeto ainda esteja no plano grátis (Spark). É ideal para protótipos ou pequenas aplicações Android/iOS. 
E tal como as outras soluções de pesquisa de texto para o Firebase, esta biblioteca funciona através de Cloud Functions.

Como começar

Vou assumir que você já sabe criar e fazer o deploy de Cloud Functions. Caso não, leia o segundo artigo desta série.

  1. No directório functions do seu projeto Firebase, abra o ficheiro package.json e certifique-se que a sua cloud function está a utilizar o NodeJS na versão 8:
{
// ... name, description, dependencies, etc
"engines": {
"node": "8"
}
}

2. Instale o Tocha, abrindo a terminal e utilizando o comando:

npm install tocha

3. Por fim, abra o ficheiro index.js do directório functions e importe a(s) funcionalidade(s) do Tocha que você precisa:

const functions = require('firebase-functions');
// ... você pode importar mais bibliotecas aqui ...
const tocha = require('tocha');

// Para importar Pesquisa de texto no Cloud Firestore:
exports.searchFirestore = tocha.searchFirestore;

// Para importar Pesquisa de texto na Realtime Database:
exports.searchRTDB = tocha.searchRTDB;

// ... você pode declarar mais funções aqui ...

E pronto. Agora só basta fazer o deploy das novas funções:

firebase deploy --only functions

Vamos Experimentar

Suponhamos que temos uma collection no Cloud Firestore que armazena tarefas para uma app de organização de tarefas. Vamos chamar esta collection de “tarefas”:

A collection tarefas e um dos documentos que ela contem.

Como vemos na imagem, a collection tem apenas 2 documentos, mas vamos supor que já tenhamos armazenado centenas de tarefas e já não nos lembramos à quem tínhamos de ligar para felicitar.
Vamos então utilizar o Tocha para pesquisar por tarefas que tenham a palavra “Ligar” no título. Para isso, temos de criar uma nova collection com o nome “tocha_searches”. Nesta collection vamos adicionar o seguinte documento:

{
"collectionName": "tarefas", // collection que vamos pesquisar
"fields": ["titulo"], // campo(s) a pesquisar
"query": "Ligar*" // texto a ser encontrado
}

Ao adicionar este documento, a nossa Cloud Function será invocada e se estiver tudo correto, ela irá adicionar um campo response ao nosso documento contendo:

  • isSuccessful (boolean) — este campo terá o valor true se a nossa pesquisa for bem sucedida ou false caso contrário.
  • result— se a pesquisa for bem sucedida, este campo será um array contendo as tarefas que foram encontradas como resultado da pesquisa. Nota: Se ocorrer algum erro e isSuccessful for false, o campo result não existirá.
  • errorMessage — só existe se tiver ocorrido algum erro e o valor do campo é uma String explicando a causa do erro.

Então a nossa resposta ficará algo como:

Num cenário real, só teríamos de ler o valor deste campo result e mostrá-lo na UI da nossa aplicação Android/iOS. E pronto, pesquisa implementada com sucesso.

Limitações

Tocha ainda é um projeto em desenvolvimento e possui algumas limitações:

  1. Firestore/RTDB Security Rules não se aplicam na pesquisa. Isto significa que todas pesquisas realizadas assumem que o utilizador autenticado é administrador e tem acesso à toda base de dados.
  2. Ainda não existe um SDK client-side para executar a pesquisa, mas já comecei a desenvolver um para android(tocha-android).

Vale lembrar que é um projeto Open Source, então você também é convidado à contribuir 🙂 O código-fonte e mais informações podem ser encontrados no GitHub:

rosariopfernandes/Tocha

Espero que esta biblioteca ajude-o no desenvolvimento de protótipos e/ou pequenas aplicações móveis com pesquisa de texto no Firebase. 🙂


Caso tenha alguma dúvida ou sugestão, deixe abaixo nos comentários. Se você estiver tentando usar a Tocha e teve algum problema, abra um issue no GitHub explicando o que você fez e qual foi o erro que teve.