Uma live query é uma subscription a uma consulta de banco de dados — o servidor faz push de eventos de criação, atualização e exclusão conforme acontecem. É o tempo verbal que faltava no acesso a dados: consultas normais falam no passado (“o que correspondia quando perguntei”), live queries falam no presente contínuo (“o que corresponde, à medida que muda”). A tela para de perguntar e passa a se manter certa.
Principais pontos
| Pergunta | Resposta |
|---|---|
| O que é | Uma consulta permanente — inscreva-se uma vez, receba cada mudança nos resultados |
| Os cinco eventos | create · update · delete · enter · leave |
| Por baixo do capô | Change stream do banco → correspondência de predicados → push por WebSocket |
| vs. polling | Latência de tempo real, payloads do tamanho do delta, sem carga de consulta por intervalo |
| vs. sockets crus | A camada de consultas: correspondência, eventos tipados, permissões, reconexões |
A subscription, em código
O movimento que define o conceito — pegue a consulta que você já tinha e inscreva-se nela:
// JavaScript / Node.js — Back4app JS SDK
// A live query: subscribe to a QUERY and receive its changes as events
const query = new Parse.Query('Task');
query.equalTo('assignee', currentUser);
const sub = await query.subscribe();
sub.on('create', (t) => addRow(t)); // new match appeared
sub.on('update', (t) => refreshRow(t)); // a match changed
sub.on('enter', (t) => addRow(t)); // edited INTO the result set
sub.on('leave', (t) => removeRow(t)); // edited OUT of the result set
sub.on('delete', (t) => removeRow(t)); // a match was deleted // Flutter / Dart — Back4app Flutter SDK
// A live query: subscribe to a QUERY and receive its changes as events
final liveQuery = LiveQuery();
final query = QueryBuilder<ParseObject>(ParseObject('Task'))
..whereEqualTo('assignee', currentUser);
final sub = await liveQuery.client.subscribe(query);
sub.on(LiveQueryEvent.create, (t) => addRow(t)); // new match
sub.on(LiveQueryEvent.update, (t) => refreshRow(t)); // match changed
sub.on(LiveQueryEvent.enter, (t) => addRow(t)); // edited into the set
sub.on(LiveQueryEvent.leave, (t) => removeRow(t)); // edited out of the set // iOS / Swift — Back4app Swift SDK
// A live query: subscribe to a QUERY and receive its changes as events
let query = Task.query("assignee" == currentUser)
let subscription = query.subscribeCallback
subscription?.handleEvent { _, event in
switch event {
case .created(let t): addRow(t) // new match appeared
case .updated(let t): refreshRow(t) // a match changed
case .entered(let t): addRow(t) // edited INTO the result set
case .left(let t): removeRow(t) // edited OUT of the result set
case .deleted(let t): removeRow(t)
}
} // Android / Kotlin — Back4app Android SDK
// A live query: subscribe to a QUERY and receive its changes as events
val client = ParseLiveQueryClient.Factory.getClient()
val query = ParseQuery.getQuery<ParseObject>("Task")
query.whereEqualTo("assignee", currentUser)
val sub = client.subscribe(query)
sub.handleEvent(SubscriptionHandling.Event.CREATE) { _, t -> addRow(t) }
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, t -> refreshRow(t) }
sub.handleEvent(SubscriptionHandling.Event.ENTER) { _, t -> addRow(t) }
sub.handleEvent(SubscriptionHandling.Event.LEAVE) { _, t -> removeRow(t) } O vocabulário de eventos merece sua própria tabela, porque enter e leave são o que torna isto uma subscription de consulta, e não uma notificação de tabela:
| Evento | Dispara quando… | Exemplo (inscrito em “tarefas atribuídas a mim”) |
|---|---|---|
| create | Um registro novo corresponde | Uma tarefa é criada para você |
| update | Um registro correspondente muda | O status da sua tarefa vira |
| enter | Uma edição faz um registro existente corresponder | Uma tarefa é reatribuída para você |
| leave | Uma edição faz um correspondente parar de corresponder | Sua tarefa é reatribuída a outra pessoa |
| delete | Um registro correspondente é excluído | A tarefa é removida |
O pipeline por trás do push
Duas metades, separáveis com clareza: a fonte de mudanças — o feed de escritas do próprio banco (change streams em bancos de documentos, logs de replicação nos demais) — e a camada de correspondência, que verifica cada mudança contra todos os predicados registrados e faz push exatamente aos assinantes cujos resultados mudaram, com permissões aplicadas por assinante. O protocolo aberto LiveQuery é uma implementação de referência legível do formato inteiro.
Live queries vs. polling vs. SSE vs. WebSockets
| Abordagem | Latência | Payload | Custo no servidor | Você constrói |
|---|---|---|---|---|
| Polling | Intervalo do poll | Refetch completo a cada vez | Consultas × clientes × frequência | Timers, diffing |
| Long polling | Quase tempo real | Resposta completa por evento | Requests seguradas | Encanamento de fallback |
| SSE | Tempo real | Delta | Streams, só de ida | Design de eventos |
| WebSockets crus | Tempo real | O que você definir | Conexões + seu fan-out | Tudo |
| Live queries | Tempo real | Eventos por mudança | Correspondência + conexões (gerenciadas) | A consulta |
A última coluna é o argumento: com sockets crus você constrói o protocolo de mensagens, o roteamento, as checagens de permissão e o reconectar-e-atualizar; com live queries o predicado é o protocolo e a plataforma é dona do resto.
Casos de uso comuns
- Chat e caixas de entrada — inscreva-se nas mensagens da conversa; a chegada é um evento, não um refresh.
- Dashboards ao vivo — pedidos, métricas, frotas: a consulta define a visão, os eventos a mantêm verdadeira.
- Apps colaborativos — quadros de tarefas e documentos compartilhados em que as edições de cinco pessoas se entrelaçam em segundos.
- Presença e status — quem está online, o que está em andamento — enter/leave fazendo seu trabalho de precisão.
- Telas operacionais — consoles de suporte e visões de admin que precisam refletir a produção agora, não no último refresh.
Poll, push ou subscription? Matriz de decisão
| Escolha live queries quando… | Ferramentas mais simples bastam quando… |
|---|---|
| Usuários observam dados compartilhados que mudam | Os dados mudam raramente — poll gentil ou refetch ao focar |
| As mudanças vêm de muitos escritores e caminhos | Um único escritor poderia só enviar via SSE |
| A visão é naturalmente uma consulta | A mensagem não tem formato de dado (use sockets diretamente) |
| Permissões precisam filtrar o que cada um vê | Tudo é broadcast público |
| Você prefere não ser dono da infraestrutura de fan-out | Você já opera uma plataforma de tempo real |
A disciplina de cliente que mantém subscriptions saudáveis, seja qual for a escolha: inscreva-se de forma estreita (predicados seletivos em campos indexados) e cancele a subscription quando a tela fechar — consultas permanentes são estado no servidor, e telas que as vazam acumulam custo invisivelmente.
Limitações e trade-offs
- Correspondência é carga de verdade. Cada escrita é verificada contra os predicados registrados; milhares de subscriptions amplas em classes quentes multiplicam isso — seletividade é a alavanca.
- Conexões são estado. A frota de sockets precisa de afinidade, heartbeats e backplanes de fan-out — plataformas gerenciadas existem exatamente porque isso é trabalho pesado sem diferencial.
- Reconexões precisam de catch-up. Um cliente que ficou offline perdeu eventos; fluxos robustos reexecutam a consulta base ao reinscrever-se, em vez de confiar que o intervalo foi quieto.
- Ordenação e entrega têm formato at-least-once. Handlers de eventos idempotentes (aplique por ID do objeto, não por append) absorvem o duplicado ocasional com elegância.
- Nem tudo quer uma subscription. Dados raramente vistos e raramente alterados são território de polling; live queries pagam seu custo onde olhos e escritas são ambos frequentes.
Live queries no Back4app
O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. O Live Query é sua camada de tempo real, e as abas de código acima são toda a história do cliente: o mesmo query builder que você já usa, uma chamada de subscribe, cinco eventos tipados — com ACLs verificadas por assinante para que o tempo real nunca passe por cima do modelo de permissões, e com a frota de WebSockets, os change streams e o fan-out rodando como infraestrutura gerenciada. Habilite o Live Query em uma classe no dashboard, inscreva-se de qualquer SDK, e o presente contínuo vira uma feature, não um projeto.
Perguntas frequentes
O que é uma live query?
Uma subscription permanente a uma consulta de banco de dados: em vez de perguntar uma vez e receber um snapshot, você se inscreve na consulta e o servidor faz push de um evento sempre que o conjunto de resultados muda — um registro correspondente criado, atualizado, excluído ou editado para dentro ou para fora dos resultados. Sua tela para de fazer polling e começa a escutar.
Qual a diferença entre uma live query e uma consulta normal?
Tempo de vida. Uma consulta normal roda, retorna e acabou — a resposta começa a envelhecer imediatamente. Uma live query fica registrada no servidor: os resultados iniciais chegam do mesmo jeito, e depois eventos de mudança pontuais os mantêm atuais até você cancelar a subscription. Mesma linguagem de predicados, relação oposta com o tempo.
Como as live queries funcionam por baixo do capô?
Duas metades unidas: uma fonte de mudanças e um transporte. O banco de dados emite seu fluxo de escritas — via change streams, logs de replicação ou triggers — e um servidor de subscriptions compara cada mudança com os predicados das consultas registradas, fazendo push dos eventos relevantes aos assinantes por WebSockets. O SDK do cliente embrulha o ciclo de vida do socket, e o seu código só vê eventos tipados.
O que são os eventos enter e leave?
O par sutil que torna precisas as subscriptions de consulta. Enter dispara quando um registro existente é editado e passa a corresponder ao seu predicado; leave dispara quando uma edição faz ele deixar de corresponder. Uma tarefa reatribuída a você entra na sua subscription de "atribuídas a mim" sem ter sido criada; reatribuída a outra pessoa, ela sai sem ter sido excluída. Create, update e delete cobrem o resto.
Por que live queries são melhores que polling?
De três formas ao mesmo tempo: latência — as mudanças chegam em tempo real, não no próximo poll; banda — os eventos carregam só o que mudou, em vez de rebuscar tudo; e carga — o servidor faz correspondência por mudança, em vez de rodar consultas completas por cliente a cada intervalo. Polling a cada poucos segundos é simulação; subscriptions são a coisa de verdade.
O que as live queries acrescentam sobre WebSockets crus?
O cérebro de consultas. Um socket cru move mensagens; todo o resto — quais clientes se importam com quais mudanças, o que os eventos significam, quem pode ver o quê, atualizar-se depois de reconectar — é código que você escreve. Uma camada de live query faz a correspondência de predicados no servidor, tipa os eventos, aplica permissões por assinante e gerencia o ciclo de vida do socket. É a diferença entre um transporte e uma feature.
Subscriptions GraphQL são a mesma coisa que live queries?
Mesma família, gatilho diferente. Subscriptions GraphQL disparam em eventos nomeados que você define — uma mutation publica, os assinantes recebem. Live queries disparam quando o conjunto de resultados de uma consulta muda — sem fiação de eventos, o predicado é a subscription. Ambas rodam sobre WebSockets; live queries trocam o design explícito de eventos pela cobertura automática de todo caminho de escrita.
Como as live queries escalam?
Em dois eixos: conexões — milhares de sockets abertos distribuídos entre servidores de subscription atrás de um backplane de pub/sub — e correspondência — cada escrita verificada contra os predicados registrados, e é por isso que subscriptions seletivas em campos indexados importam. Plataformas gerenciadas operam os dois eixos por você; a disciplina do lado do cliente é inscrever-se de forma estreita e cancelar quando a tela fecha.