获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

Ler e gravar dados na Web

(Opcional) Protótipo e teste com Firebase Local Emulator Suite

Antes de falar sobre como seu aplicativo lê e grava no Realtime Database, vamos apresentar um conjunto de ferramentas que você pode usar para prototipar e testar a funcionalidade do Realtime Database: Firebase Local Emulator Suite. Se você está experimentando diferentes modelos de dados, otimizando suas regras de segurança ou trabalhando para encontrar a maneira mais econômica de interagir com o back-end, poder trabalhar localmente sem implantar serviços ao vivo pode ser uma ótima ideia.

Um emulador do Realtime Database faz parte do Local Emulator Suite, que permite que seu aplicativo interaja com o conteúdo e a configuração do banco de dados emulado, bem como, opcionalmente, com os recursos do projeto emulado (funções, outros bancos de dados e regras de segurança).

Usar o emulador do Realtime Database envolve apenas algumas etapas:

  1. Adicionando uma linha de código à configuração de teste do seu aplicativo para se conectar ao emulador.
  2. Na raiz do diretório local do projeto, execute firebase emulators:start .
  3. Fazer chamadas a partir do código de protótipo do seu aplicativo usando um SDK da plataforma do Realtime Database como de costume ou usando a API REST do Realtime Database.

Um passo a passo detalhado envolvendo o Realtime Database e o Cloud Functions está disponível. Você também deve dar uma olhada na introdução do Local Emulator Suite .

Obter uma referência de banco de dados

Para ler ou gravar dados do banco de dados, você precisa de uma instância de firebase.database.Reference :

Web version 9

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web version 8

var database = firebase.database();

Gravar dados

Este documento aborda os fundamentos da recuperação de dados e como ordenar e filtrar dados do Firebase.

Os dados do Firebase são recuperados anexando um ouvinte assíncrono a um firebase.database.Reference . O ouvinte é acionado uma vez para o estado inicial dos dados e novamente sempre que os dados forem alterados.

Operações básicas de gravação

Para operações básicas de gravação, você pode usar set() para salvar dados em uma referência especificada, substituindo quaisquer dados existentes nesse caminho. Por exemplo, um aplicativo de blog social pode adicionar um usuário com set() da seguinte maneira:

Web version 9

import { getDatabase, ref, set } from "firebase/database";

function writeUserData(userId, name, email, imageUrl) {
  const db = getDatabase();
  set(ref(db, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Web version 8

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

O uso set() substitui os dados no local especificado, incluindo quaisquer nós filhos.

Ler dados

Ouça eventos de valor

Para ler os dados em um caminho e ouvir as alterações, use onValue() para observar os eventos. Você pode usar este evento para ler instantâneos estáticos do conteúdo em um determinado caminho, conforme eles existiam no momento do evento. Esse método é acionado uma vez quando o ouvinte é anexado e novamente toda vez que os dados, incluindo filhos, são alterados. O retorno de chamada do evento recebe um instantâneo contendo todos os dados naquele local, incluindo dados filho. Se não houver dados, o instantâneo retornará false quando você chamar exists() e null quando chamar val() nele.

O exemplo a seguir demonstra um aplicativo de blog social recuperando a contagem de estrelas de uma postagem do banco de dados:

Web version 9

import { getDatabase, ref, onValue} from "firebase/database";

const db = getDatabase();
const starCountRef = ref(db, 'posts/' + postId + '/starCount');
onValue(starCountRef, (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Web version 8

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

O ouvinte recebe um snapshot que contém os dados no local especificado no banco de dados no momento do evento. Você pode recuperar os dados no snapshot com o método val() .

Ler dados uma vez

Leia os dados uma vez com get ()

O SDK foi projetado para gerenciar interações com servidores de banco de dados, independentemente de seu aplicativo estar online ou offline.

Geralmente, você deve usar as técnicas de evento de valor descritas acima para ler dados para ser notificado sobre atualizações nos dados do back-end. As técnicas de ouvinte reduzem seu uso e cobrança e são otimizadas para oferecer aos usuários a melhor experiência à medida que ficam online e offline.

Se você precisar dos dados apenas uma vez, poderá usar get() para obter um instantâneo dos dados do banco de dados. Se, por qualquer motivo, get() não puder retornar o valor do servidor, o cliente testará o cache de armazenamento local e retornará um erro se o valor ainda não for encontrado.

O uso desnecessário de get() pode aumentar o uso da largura de banda e levar à perda de desempenho, o que pode ser evitado usando um ouvinte em tempo real, conforme mostrado acima.

Web version 9

import { getDatabase, ref, child, get } from "firebase/database";

const dbRef = ref(getDatabase());
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Web version 8

const dbRef = firebase.database().ref();
dbRef.child("users").child(userId).get().then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Leia os dados uma vez com um observador

Em alguns casos, você pode querer que o valor do cache local seja retornado imediatamente, em vez de verificar um valor atualizado no servidor. Nesses casos, você pode usar once() para obter os dados do cache do disco local imediatamente.

Isso é útil para dados que precisam ser carregados apenas uma vez e não devem ser alterados com frequência ou exigir escuta ativa. Por exemplo, o aplicativo de blog nos exemplos anteriores usa este método para carregar o perfil de um usuário quando ele começa a criar uma nova postagem:

Web version 9

import { getDatabase, ref, onValue } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const userId = auth.currentUser.uid;
return onValue(ref(db, '/users/' + userId), (snapshot) => {
  const username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
}, {
  onlyOnce: true
});

Web version 8

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

Atualizando ou excluindo dados

Atualizar campos específicos

Para gravar simultaneamente em filhos específicos de um nó sem sobrescrever outros nós filhos, use o método update() .

Ao chamar update() , você pode atualizar valores filho de nível inferior especificando um caminho para a chave. Se os dados forem armazenados em vários locais para dimensionar melhor, você poderá atualizar todas as instâncias desses dados usando distribuição de dados .

Por exemplo, um aplicativo de blog social pode criar uma postagem e atualizá-la simultaneamente para o feed de atividade recente e o feed de atividade do usuário da postagem usando um código como este:

Web version 9

import { getDatabase, ref, child, push, update } from "firebase/database";

function writeNewPost(uid, username, picture, title, body) {
  const db = getDatabase();

  // A post entry.
  const postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  const newPostKey = push(child(ref(db), 'posts')).key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  const updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return update(ref(db), updates);
}

Web version 8

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

Este exemplo usa push() para criar uma postagem no nó contendo postagens para todos os usuários em /posts/$postid e simultaneamente recuperar a chave. A chave pode então ser usada para criar uma segunda entrada nas postagens do usuário em /user-posts/$userid/$postid .

Usando esses caminhos, você pode executar atualizações simultâneas em vários locais na árvore JSON com uma única chamada para update() , como este exemplo cria a nova postagem em ambos os locais. As atualizações simultâneas feitas dessa maneira são atômicas: todas as atualizações são bem-sucedidas ou todas as atualizações falham.

Adicionar um retorno de chamada de conclusão

Se você quiser saber quando seus dados foram confirmados, você pode adicionar um retorno de chamada de conclusão. Ambos set() e update() recebem um retorno de chamada de conclusão opcional que é chamado quando a gravação foi confirmada no banco de dados. Se a chamada não for bem-sucedida, o retorno de chamada receberá um objeto de erro indicando o motivo da falha.

Web version 9

import { getDatabase, ref, set } from "firebase/database";

const db = getDatabase();
set(ref(db, 'users/' + userId), {
  username: name,
  email: email,
  profile_picture : imageUrl
})
.then(() => {
  // Data saved successfully!
})
.catch((error) => {
  // The write failed...
});

Web version 8

firebase.database().ref('users/' + userId).set({
  username: name,
  email: email,
  profile_picture : imageUrl
}, (error) => {
  if (error) {
    // The write failed...
  } else {
    // Data saved successfully!
  }
});

Excluir dados

A maneira mais simples de excluir dados é chamar remove() em uma referência ao local desses dados.

Você também pode excluir especificando null como o valor para outra operação de gravação, como set() ou update() . Você pode usar essa técnica com update() para excluir vários filhos em uma única chamada de API.

Receba uma Promise

Para saber quando seus dados são confirmados no servidor Firebase Realtime Database, você pode usar um Promise . Ambos set() e update() podem retornar um Promise que você pode usar para saber quando a gravação é confirmada no banco de dados.

Desanexar ouvintes

Os retornos de chamada são removidos chamando o método off() na referência do banco de dados do Firebase.

Você pode remover um único ouvinte passando-o como um parâmetro para off() . Chamar off() no local sem argumentos remove todos os ouvintes naquele local.

Chamar off() em um ouvinte pai não remove automaticamente os ouvintes registrados em seus nós filhos; off() também deve ser chamado em qualquer ouvinte filho para remover o retorno de chamada.

Salvar dados como transações

Ao trabalhar com dados que podem ser corrompidos por modificações simultâneas, como contadores incrementais, você pode usar uma operação de transação . Você pode fornecer a essa operação uma função de atualização e um retorno de chamada de conclusão opcional. A função de atualização pega o estado atual dos dados como um argumento e retorna o novo estado desejado que você gostaria de escrever. Se outro cliente gravar no local antes de seu novo valor ser gravado com êxito, sua função de atualização será chamada novamente com o novo valor atual e a gravação será repetida.

Por exemplo, no exemplo de aplicativo de blog social, você pode permitir que os usuários marquem e excluam postagens com estrela e acompanhem quantas estrelas uma postagem recebeu da seguinte maneira:

Web version 9

import { getDatabase, ref, runTransaction } from "firebase/database";

function toggleStar(uid) {
  const db = getDatabase();
  const postRef = ref(db, '/posts/foo-bar-123');

  runTransaction(postRef, (post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Web version 8

function toggleStar(postRef, uid) {
  postRef.transaction((post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

O uso de uma transação evita que a contagem de estrelas seja incorreta se vários usuários marcarem a mesma postagem ao mesmo tempo ou se o cliente tiver dados desatualizados. Se a transação for rejeitada, o servidor retorna o valor atual para o cliente, que executa novamente a transação com o valor atualizado. Isso se repete até que a transação seja aceita ou você cancele a transação.

Incrementos atômicos do lado do servidor

No caso de uso acima, estamos escrevendo dois valores no banco de dados: o ID do usuário que marca/desmarca a postagem e a contagem de estrelas incrementada. Se já sabemos que o usuário está marcando a postagem, podemos usar uma operação de incremento atômico em vez de uma transação.

function addStar(uid, key) {
  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  firebase.database().ref().update(updates);
}

Esse código não usa uma operação de transação, portanto, não é executado novamente automaticamente se houver uma atualização conflitante. No entanto, como a operação de incremento ocorre diretamente no servidor de banco de dados, não há possibilidade de conflito.

Se você deseja detectar e rejeitar conflitos específicos do aplicativo, como um usuário marcando uma postagem que ele já marcou antes, você deve escrever regras de segurança personalizadas para esse caso de uso.

Trabalhe com dados off-line

Se um cliente perder sua conexão de rede, seu aplicativo continuará funcionando corretamente.

Cada cliente conectado a um banco de dados Firebase mantém sua própria versão interna de todos os dados ativos. Quando os dados são gravados, eles são gravados primeiro nesta versão local. O cliente Firebase sincroniza esses dados com os servidores de banco de dados remotos e com outros clientes com base no "melhor esforço".

Como resultado, todas as gravações no banco de dados acionam eventos locais imediatamente, antes que qualquer dado seja gravado no servidor. Isso significa que seu aplicativo permanece responsivo, independentemente da latência ou conectividade da rede.

Depois que a conectividade é restabelecida, seu aplicativo recebe o conjunto apropriado de eventos para que o cliente sincronize com o estado atual do servidor, sem precisar escrever nenhum código personalizado.

Falaremos mais sobre o comportamento off-line em Saiba mais sobre os recursos on-line e off-line .

Próximos passos

,

(Opcional) Protótipo e teste com Firebase Local Emulator Suite

Antes de falar sobre como seu aplicativo lê e grava no Realtime Database, vamos apresentar um conjunto de ferramentas que você pode usar para prototipar e testar a funcionalidade do Realtime Database: Firebase Local Emulator Suite. Se você está experimentando diferentes modelos de dados, otimizando suas regras de segurança ou trabalhando para encontrar a maneira mais econômica de interagir com o back-end, poder trabalhar localmente sem implantar serviços ao vivo pode ser uma ótima ideia.

Um emulador do Realtime Database faz parte do Local Emulator Suite, que permite que seu aplicativo interaja com o conteúdo e a configuração do banco de dados emulado, bem como, opcionalmente, com os recursos do projeto emulado (funções, outros bancos de dados e regras de segurança).

Usar o emulador do Realtime Database envolve apenas algumas etapas:

  1. Adicionando uma linha de código à configuração de teste do seu aplicativo para se conectar ao emulador.
  2. Na raiz do diretório local do projeto, execute firebase emulators:start .
  3. Fazer chamadas a partir do código de protótipo do seu aplicativo usando um SDK da plataforma do Realtime Database como de costume ou usando a API REST do Realtime Database.

Um passo a passo detalhado envolvendo o Realtime Database e o Cloud Functions está disponível. Você também deve dar uma olhada na introdução do Local Emulator Suite .

Obter uma referência de banco de dados

Para ler ou gravar dados do banco de dados, você precisa de uma instância de firebase.database.Reference :

Web version 9

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web version 8

var database = firebase.database();

Gravar dados

Este documento aborda os fundamentos da recuperação de dados e como ordenar e filtrar dados do Firebase.

Os dados do Firebase são recuperados anexando um ouvinte assíncrono a um firebase.database.Reference . O ouvinte é acionado uma vez para o estado inicial dos dados e novamente sempre que os dados forem alterados.

Operações básicas de gravação

Para operações básicas de gravação, você pode usar set() para salvar dados em uma referência especificada, substituindo quaisquer dados existentes nesse caminho. Por exemplo, um aplicativo de blog social pode adicionar um usuário com set() da seguinte maneira:

Web version 9

import { getDatabase, ref, set } from "firebase/database";

function writeUserData(userId, name, email, imageUrl) {
  const db = getDatabase();
  set(ref(db, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Web version 8

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

O uso set() substitui os dados no local especificado, incluindo quaisquer nós filhos.

Ler dados

Ouça eventos de valor

Para ler os dados em um caminho e ouvir as alterações, use onValue() para observar os eventos. Você pode usar este evento para ler instantâneos estáticos do conteúdo em um determinado caminho, conforme eles existiam no momento do evento. Esse método é acionado uma vez quando o ouvinte é anexado e novamente toda vez que os dados, incluindo filhos, são alterados. O retorno de chamada do evento recebe um instantâneo contendo todos os dados naquele local, incluindo dados filho. Se não houver dados, o instantâneo retornará false quando você chamar exists() e null quando chamar val() nele.

O exemplo a seguir demonstra um aplicativo de blog social recuperando a contagem de estrelas de uma postagem do banco de dados:

Web version 9

import { getDatabase, ref, onValue} from "firebase/database";

const db = getDatabase();
const starCountRef = ref(db, 'posts/' + postId + '/starCount');
onValue(starCountRef, (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Web version 8

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

O ouvinte recebe um snapshot que contém os dados no local especificado no banco de dados no momento do evento. Você pode recuperar os dados no snapshot com o método val() .

Ler dados uma vez

Leia os dados uma vez com get ()

O SDK foi projetado para gerenciar interações com servidores de banco de dados, independentemente de seu aplicativo estar online ou offline.

Geralmente, você deve usar as técnicas de evento de valor descritas acima para ler dados para ser notificado sobre atualizações nos dados do back-end. As técnicas de ouvinte reduzem seu uso e cobrança e são otimizadas para oferecer aos usuários a melhor experiência à medida que ficam online e offline.

Se você precisar dos dados apenas uma vez, poderá usar get() para obter um instantâneo dos dados do banco de dados. Se, por qualquer motivo, get() não puder retornar o valor do servidor, o cliente testará o cache de armazenamento local e retornará um erro se o valor ainda não for encontrado.

O uso desnecessário de get() pode aumentar o uso da largura de banda e levar à perda de desempenho, o que pode ser evitado usando um ouvinte em tempo real, conforme mostrado acima.

Web version 9

import { getDatabase, ref, child, get } from "firebase/database";

const dbRef = ref(getDatabase());
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Web version 8

const dbRef = firebase.database().ref();
dbRef.child("users").child(userId).get().then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Leia os dados uma vez com um observador

Em alguns casos, você pode querer que o valor do cache local seja retornado imediatamente, em vez de verificar um valor atualizado no servidor. Nesses casos, você pode usar once() para obter os dados do cache do disco local imediatamente.

Isso é útil para dados que precisam ser carregados apenas uma vez e não devem ser alterados com frequência ou exigir escuta ativa. Por exemplo, o aplicativo de blog nos exemplos anteriores usa este método para carregar o perfil de um usuário quando ele começa a criar uma nova postagem:

Web version 9

import { getDatabase, ref, onValue } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const userId = auth.currentUser.uid;
return onValue(ref(db, '/users/' + userId), (snapshot) => {
  const username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
}, {
  onlyOnce: true
});

Web version 8

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

Atualizando ou excluindo dados

Atualizar campos específicos

Para gravar simultaneamente em filhos específicos de um nó sem sobrescrever outros nós filhos, use o método update() .

Ao chamar update() , você pode atualizar valores filho de nível inferior especificando um caminho para a chave. Se os dados forem armazenados em vários locais para dimensionar melhor, você poderá atualizar todas as instâncias desses dados usando distribuição de dados .

Por exemplo, um aplicativo de blog social pode criar uma postagem e atualizá-la simultaneamente para o feed de atividade recente e o feed de atividade do usuário da postagem usando um código como este:

Web version 9

import { getDatabase, ref, child, push, update } from "firebase/database";

function writeNewPost(uid, username, picture, title, body) {
  const db = getDatabase();

  // A post entry.
  const postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  const newPostKey = push(child(ref(db), 'posts')).key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  const updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return update(ref(db), updates);
}

Web version 8

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

Este exemplo usa push() para criar uma postagem no nó contendo postagens para todos os usuários em /posts/$postid e simultaneamente recuperar a chave. A chave pode então ser usada para criar uma segunda entrada nas postagens do usuário em /user-posts/$userid/$postid .

Usando esses caminhos, você pode executar atualizações simultâneas em vários locais na árvore JSON com uma única chamada para update() , como este exemplo cria a nova postagem em ambos os locais. As atualizações simultâneas feitas dessa maneira são atômicas: todas as atualizações são bem-sucedidas ou todas as atualizações falham.

Adicionar um retorno de chamada de conclusão

Se você quiser saber quando seus dados foram confirmados, você pode adicionar um retorno de chamada de conclusão. Ambos set() e update() recebem um retorno de chamada de conclusão opcional que é chamado quando a gravação foi confirmada no banco de dados. Se a chamada não for bem-sucedida, o retorno de chamada receberá um objeto de erro indicando o motivo da falha.

Web version 9

import { getDatabase, ref, set } from "firebase/database";

const db = getDatabase();
set(ref(db, 'users/' + userId), {
  username: name,
  email: email,
  profile_picture : imageUrl
})
.then(() => {
  // Data saved successfully!
})
.catch((error) => {
  // The write failed...
});

Web version 8

firebase.database().ref('users/' + userId).set({
  username: name,
  email: email,
  profile_picture : imageUrl
}, (error) => {
  if (error) {
    // The write failed...
  } else {
    // Data saved successfully!
  }
});

Excluir dados

A maneira mais simples de excluir dados é chamar remove() em uma referência ao local desses dados.

Você também pode excluir especificando null como o valor para outra operação de gravação, como set() ou update() . Você pode usar essa técnica com update() para excluir vários filhos em uma única chamada de API.

Receba uma Promise

Para saber quando seus dados são confirmados no servidor Firebase Realtime Database, você pode usar um Promise . Ambos set() e update() podem retornar um Promise que você pode usar para saber quando a gravação é confirmada no banco de dados.

Desanexar ouvintes

Os retornos de chamada são removidos chamando o método off() na referência do banco de dados do Firebase.

Você pode remover um único ouvinte passando-o como um parâmetro para off() . Chamar off() no local sem argumentos remove todos os ouvintes naquele local.

Chamar off() em um ouvinte pai não remove automaticamente os ouvintes registrados em seus nós filhos; off() também deve ser chamado em qualquer ouvinte filho para remover o retorno de chamada.

Salvar dados como transações

Ao trabalhar com dados que podem ser corrompidos por modificações simultâneas, como contadores incrementais, você pode usar uma operação de transação . Você pode fornecer a essa operação uma função de atualização e um retorno de chamada de conclusão opcional. A função de atualização pega o estado atual dos dados como um argumento e retorna o novo estado desejado que você gostaria de escrever. Se outro cliente gravar no local antes de seu novo valor ser gravado com êxito, sua função de atualização será chamada novamente com o novo valor atual e a gravação será repetida.

Por exemplo, no exemplo de aplicativo de blog social, você pode permitir que os usuários marquem e excluam postagens com estrela e acompanhem quantas estrelas uma postagem recebeu da seguinte maneira:

Web version 9

import { getDatabase, ref, runTransaction } from "firebase/database";

function toggleStar(uid) {
  const db = getDatabase();
  const postRef = ref(db, '/posts/foo-bar-123');

  runTransaction(postRef, (post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Web version 8

function toggleStar(postRef, uid) {
  postRef.transaction((post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

O uso de uma transação evita que a contagem de estrelas seja incorreta se vários usuários marcarem a mesma postagem ao mesmo tempo ou se o cliente tiver dados desatualizados. Se a transação for rejeitada, o servidor retorna o valor atual para o cliente, que executa novamente a transação com o valor atualizado. Isso se repete até que a transação seja aceita ou você cancele a transação.

Incrementos atômicos do lado do servidor

No caso de uso acima, estamos escrevendo dois valores no banco de dados: o ID do usuário que marca/desmarca a postagem e a contagem de estrelas incrementada. Se já sabemos que o usuário está marcando a postagem, podemos usar uma operação de incremento atômico em vez de uma transação.

function addStar(uid, key) {
  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  firebase.database().ref().update(updates);
}

Esse código não usa uma operação de transação, portanto, não é executado novamente automaticamente se houver uma atualização conflitante. No entanto, como a operação de incremento ocorre diretamente no servidor de banco de dados, não há possibilidade de conflito.

Se você deseja detectar e rejeitar conflitos específicos do aplicativo, como um usuário marcando uma postagem que ele já marcou antes, você deve escrever regras de segurança personalizadas para esse caso de uso.

Trabalhe com dados off-line

Se um cliente perder sua conexão de rede, seu aplicativo continuará funcionando corretamente.

Cada cliente conectado a um banco de dados Firebase mantém sua própria versão interna de todos os dados ativos. Quando os dados são gravados, eles são gravados primeiro nesta versão local. O cliente Firebase sincroniza esses dados com os servidores de banco de dados remotos e com outros clientes com base no "melhor esforço".

Como resultado, todas as gravações no banco de dados acionam eventos locais imediatamente, antes que qualquer dado seja gravado no servidor. Isso significa que seu aplicativo permanece responsivo, independentemente da latência ou conectividade da rede.

Depois que a conectividade é restabelecida, seu aplicativo recebe o conjunto apropriado de eventos para que o cliente sincronize com o estado atual do servidor, sem precisar escrever nenhum código personalizado.

Falaremos mais sobre o comportamento off-line em Saiba mais sobre os recursos on-line e off-line .

Próximos passos