Cache com o Firebase

O Looker Studio tem um sistema próprio de cache para relatórios. Ao criar seu conector, você pode implementar um cache personalizado para otimizar relatórios e evitar as limitações de taxa de APR.

Por exemplo, imagine que você esteja criando um conector que fornece dados meteorológicos históricos dos últimos sete dias para um CEP específico. Ele começa a ficar muito conhecido, mas a API externa que serve de origem para você buscar os dados tem limitações rígidas de taxa. Como a API só atualiza os dados diariamente, não é necessário buscar as mesmas informações várias vezes por dia para um CEP específico. Usando este guia, você pode implementar um cache diário para cada CEP.

Requisitos

  • Um Firebase Realtime Database. Se você não tem acesso a um, crie um projeto do Google Cloud Platform (GCP) e siga o guia de primeiros passos para criar sua própria instância do Firebase Realtime Database.
  • Uma conta de serviço do GCP para ler e gravar dados do Firebase Realtime Database.
  • Um conector da comunidade que busca dados de uma origem.

Limitações

  • Esta solução não pode ser usada com o Advanced Services do Looker Studio. Quando você usa o Advanced Services do Looker Studio, seu código de conector no Apps Script não tem acesso aos dados. Portanto, não é possível armazenar os dados em cache usando o Apps Script.
  • Editores e visualizadores de relatórios não podem redefinir esse cache específico.

Solução

Implementar uma conta de serviço

  1. Crie uma conta de serviço no seu projeto do Google Cloud.
  2. Essa conta precisa ter acesso ao BigQuery no projeto do Google Cloud.
    • Papéis de gerenciamento de identidade e acesso (IAM) necessários: Firebase Admin
  3. Faça o download do arquivo JSON para usar as chaves das contas de serviço. Armazene o conteúdo do arquivo nas propriedades de script do projeto do seu conector. Depois de adicionar as chaves, elas vão aparecer desta forma na interface do Apps Script:
    Salvar chaves de conta de serviço nas propriedades de script
  4. Inclua a biblioteca OAuth2 para Apps Script no seu projeto do Apps Script.
  5. Implemente o código OAuth2 necessário para a conta de serviço:
firestore-cache/src/firebase.js
var SERVICE_ACCOUNT_CREDS = 'SERVICE_ACCOUNT_CREDS';
var SERVICE_ACCOUNT_KEY = 'private_key';
var SERVICE_ACCOUNT_EMAIL = 'client_email';
var BILLING_PROJECT_ID = 'project_id';

var scriptProperties = PropertiesService.getScriptProperties();

/**
 * Copy the entire credentials JSON file from creating a service account in GCP.
 * Service account should have `Firebase Admin` IAM role.
 */
function getServiceAccountCreds() {
  return JSON.parse(scriptProperties.getProperty(SERVICE_ACCOUNT_CREDS));
}

function getOauthService() {
  var serviceAccountCreds = getServiceAccountCreds();
  var serviceAccountKey = serviceAccountCreds[SERVICE_ACCOUNT_KEY];
  var serviceAccountEmail = serviceAccountCreds[SERVICE_ACCOUNT_EMAIL];

  return OAuth2.createService('FirebaseCache')
    .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(serviceAccountKey)
    .setIssuer(serviceAccountEmail)
    .setPropertyStore(scriptProperties)
    .setCache(CacheService.getScriptCache())
    .setScope([
      'https://www.googleapis.com/auth/userinfo.email',
      'https://www.googleapis.com/auth/firebase.database'
    ]);
}

Implementar o código para ler e gravar no Firebase

Você usará a API REST do Firebase Database para ler e gravar no Firebase Realtime Database. O código a seguir implementa os métodos necessários para acessar essa API.

Implementar o código getData()

A estrutura do seu código getData() atual sem armazenamento em cache terá esta aparência:

firestore-cache/src/without-caching.js
/*
 * This file is only to demonstrate how the `getData()` fucntion would look
 * like without the Firebase Realtime Database caching. It is not a part of
 * the connector code and should not be included in Apps Script / Clasp.
 */

function getData(request) {
  var requestedFields = getFields().forIds(
    request.fields.map(function(field) {
      return field.name;
    })
  );

  var fetchedData = fetchAndParseData(request);
  var data = getFormattedData(fetchedData, requestedFields);

  return {
    schema: requestedFields.build(),
    rows: data
  };
}

Para usar o armazenamento em cache no seu código getData(), siga estas etapas:

  1. Defina a "unidade" ou o "bloco" de dados que será armazenado em cache.
  2. Crie uma chave exclusiva para armazenar a unidade mínima de dados no cache.
    No exemplo de implementação, o zipcode de configparams está sendo usado como chave.
    Opcional: para o cache por usuário, crie uma chave composta de chave-base e identidade do usuário. Exemplo de implementação:
    js var baseKey = getBaseKey(request); var userEmail = Session.getEffectiveUser().getEmail(); var hasheduserEmail = getHashedValue(userEmail); var compositeKey = baseKey + hasheduserEmail;

  3. Se houver dados armazenados em cache, verifique se ele é recente.
    No exemplo, os dados armazenados em cache para um CEP específico são salvos com a data atual. Quando os dados são recuperados do cache, a data dele é comparada com a atual.

    var cacheForZipcode = {
      data: <data being cached>,
      ymd: <current date in YYYYMMDD format>
    }
    
  4. Se não houver dados armazenados ou eles não forem recentes, faça uma busca na origem e armazene-os em cache.

No exemplo a seguir, main.js inclui o código getData() com o armazenamento em cache implementado.

Exemplo de código

Outros recursos

O conector da UX no Chrome permite que milhares de usuários utilizem um painel com base em uma tabela do BigQuery com aproximadamente 20 GB. Esse conector usa o Firebase Realtime Database com o serviço de cache do Apps Script para armazenamento em cache em duas camadas. Veja o código para saber mais sobre a implementação.