Trabalhar com listas de dados nas plataformas da Apple

Como ter uma FIRDatabaseReference

Para ler ou gravar dados no banco de dados, você precisa de uma instância de FIRDatabaseReference:

Swift

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

Como ler e gravar listas

Anexar a uma lista de dados

Use o método childByAutoId para anexar dados a uma lista em aplicativos de vários usuários. O método childByAutoId gera uma chave exclusiva sempre que um novo filho é adicionado a uma referência específica do Firebase. Ao usar essas chaves geradas automaticamente para cada novo elemento da lista, vários clientes poderão adicionar filhos no mesmo local simultaneamente sem criar conflitos de gravação. A chave exclusiva gerada por childByAutoId é baseada em um carimbo de data/hora. Portanto, os itens da lista são organizados automaticamente em ordem cronológica.

Use a referência aos novos dados retornados pelo método childByAutoId para receber o valor da chave filha que foi gerada automaticamente ou para definir dados para o filho. Chamar getKey em uma referência childByAutoId retorna a chave gerada automaticamente.

Você pode usar essas chaves para simplificar sua estrutura de dados. Para saber mais, consulte o exemplo de distribuição de dados.

Detectar eventos filho

Eventos filhos são acionados em resposta a operações específicas que ocorrem nos filhos de um nó de uma operação, como a adição de um novo filho por meio do método childByAutoId ou a atualização de um filho pelo método updateChildValues.

Tipo de evento Uso normal
FIRDataEventTypeChildAdded Recuperar listas de itens ou detectar adições a uma lista de itens. Este evento é acionado uma vez para cada filho e sempre que um novo filho for adicionado ao caminho especificado. O listener recebe um snapshot que contém os dados do novo filho.
FIRDataEventTypeChildChanged Detectar mudanças em itens de uma lista. Este evento é acionado sempre que um nó filho é modificado. Isso inclui modificações nos descendentes do nó filho. O snapshot transmitido para o listener de eventos contém os dados atualizados do filho.
FIRDataEventTypeChildRemoved Detectar itens sendo removidos de uma lista. Esse evento é acionado quando um filho imediato é removido. O snapshot transmitido ao bloco de retorno de chamada contém os dados do filho removido.
FIRDataEventTypeChildMoved Detectar mudanças na ordem dos itens em uma lista ordenada. Este evento é acionado sempre que uma atualização causa mudança na ordem do filho. Ele é usado com dados ordenados por queryOrderedByChild ou queryOrderedByValue.

Juntos, cada um desses métodos pode ser útil para detectar alterações em um nó específico de um banco de dados. Por exemplo, um app de blog com recursos sociais pode usar esses métodos em conjunto para monitorar atividade nos comentários de uma postagem, conforme mostrado abaixo:

Swift

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

Detectar eventos de valor

Detectar eventos filho é a maneira recomendada para ler listas de dados. Porém, há situações em que é útil detectar eventos de valor em uma referência de lista.

Anexar um observador FIRDataEventTypeValue a uma lista de dados retornará a lista inteira de dados como um DataSnapshot único que pode ser retornado para acessar filhos individuais.

Mesmo quando há apenas uma correspondência para a consulta, o snapshot ainda é uma lista, mas contém somente um item. Para acessar o item, é necessário retornar o resultado:

Swift

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

Este padrão pode ser útil quando você quiser buscar todos os filhos de uma lista em uma única operação em vez de detectar eventos mais filhos.

Como classificar e filtrar dados

É possível usar a classe FIRDatabaseQuery do Realtime Database para recuperar dados classificados por chave, valor ou valor de filho. Também é possível filtrar o resultado ordenado por um número específico de resultados ou um intervalo de chaves ou valores.

.

Ordenar dados

Para recuperar dados ordenados, comece especificando um dos métodos de ordenação para determinar como os resultados são ordenados:

Método Uso
queryOrderedByKey Ordenar resultados por chaves filhas.
queryOrderedByValue Ordenar resultados por valores filhos.
queryOrderedByChild Ordenar resultados pelo valor de uma chave filha específica ou caminho filho aninhado.

Você só pode usar um método de ordenação por vez. Chamar um método de ordenação várias vezes na mesma consulta causa um erro.

O exemplo a seguir demonstra como você pode recuperar uma lista das principais postagens de um usuário ordenadas pela contagem de estrelas:

Swift

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

Essa consulta recupera as postagens do usuário a partir do caminho do banco de dados conforme o ID do usuário, ordenadas pelo número de estrelas recebidas pelas postagens. Essa técnica de usar IDs como chaves de indexação é chamada de distribuição de dados e é explicada em mais detalhes em Estruturar seu banco de dados.

A chamada para o método queryOrderedByChild especifica a chave filha para ordenar os resultados. Neste exemplo, as postagens são classificadas pelo valor do filho "starCount" em cada postagem. Também é possível ordenar as consultas por filhos aninhados, caso os dados se pareçam com estes:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

Nesse caso, podemos ordenar nossos elementos de lista por valores aninhados na chave metrics. Para isso, é preciso especificar o caminho relacionado ao filho aninhado em nossa chamada de queryOrderedByChild.

Swift

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

Para mais informações sobre a ordenação de outros tipos de dados, consulte Como os dados de consulta são ordenados.

Filtrar dados

Para filtrar dados, combine um dos métodos de limite ou de intervalo com um método de ordenação ao criar uma consulta.

Método Uso
queryLimitedToFirst Definir o número máximo de itens para retornar a partir do início da lista ordenada de resultados.
queryLimitedToLast Definir o número máximo de itens para retornar a partir do fim da lista ordenada de resultados.
queryStartingAtValue Retornar itens maiores ou iguais à chave ou ao valor especificado, dependendo do método de ordenação escolhido.
queryStartingAfterValue Retornar itens maiores do que a chave ou o valor especificado, dependendo do método de ordenação escolhido.
queryEndingAtValue Retornar itens inferiores ou iguais à chave ou ao valor especificado, dependendo do método de ordenação escolhido.
queryEndingBeforeValue Retornar itens inferiores à chave ou ao valor especificado, dependendo do método de ordenação escolhido.
queryEqualToValue Retornar itens iguais à chave ou ao valor especificado, dependendo do método de ordenação escolhido.

Ao contrário dos métodos de ordenação, você pode combinar várias funções de limite ou de intervalo. Por exemplo, combine os métodos queryStartingAtValue e queryEndingAtValue para limitar os resultados a um intervalo especificado de valores.

Limitar o número de resultados

Os parâmetros queryLimitedToFirst e queryLimitedToLast podem ser usados para definir um número máximo de filhos a serem sincronizados para um determinado retorno de chamada. Por exemplo, se você usar queryLimitedToFirst para definir um limite de 100, inicialmente receberá até 100 retornos de chamada FIRDataEventTypeChildAdded apenas. Se você tiver menos de 100 itens armazenados no banco de dados do Firebase, um retorno de chamada FIRDataEventTypeChildAdded será acionado para cada item.

Conforme os itens forem alterados, você receberá retornos de chamada FIRDataEventTypeChildAdded para os itens que entrarem na consulta e retornos de chamada FIRDataEventTypeChildRemoved para os itens que saírem da consulta para que o número total permaneça 100.

No exemplo a seguir, demonstramos como um app de blog pode recuperar uma lista das 100 postagens mais recentes de todos os usuários:

Swift

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

Observação: este produto do Firebase não está disponível no destino Clipes de apps.
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

Filtrar por chave ou valor

O uso de queryStartingAtValue, queryStartingAfterValue, queryEndingAtValue, queryEndingBeforeValue e queryEqualToValue possibilitará escolher pontos arbitrários de início e fim para as consultas. Isso pode ser útil para paginar dados ou encontrar itens com filhos que tenham um valor específico.

Como os dados de consultas são ordenados

Nesta seção, é explicado como os dados são classificados por cada um dos métodos de ordenação na classe FIRDatabaseQuery.

queryOrderedByKey

Ao usar queryOrderedByKey para classificar seus dados, eles serão retornados em ordem crescente por chave.

  1. Filhos com uma chave que possa ser analisada como um número inteiro de 32 bits vêm primeiro, ordenados em ordem crescente.
  2. Filhos com um valor de string como chave são os próximos, ordenados lexicograficamente em ordem crescente.

queryOrderedByValue

Ao usar queryOrderedByValue, os filhos serão ordenados pelo próprio valor. Os critérios de ordenação são os mesmos de queryOrderedByChild, com a exceção de que o valor usado é o do nó, e não o de uma chave filha especificada.

queryOrderedByChild

Ao usar queryOrderedByChild, os dados que contêm a chave filha especificada serão ordenados desta maneira:

  1. Filhos com um valor nil para a chave filha especificada são os primeiros.
  2. Filhos com um valor false para a chave filha especificada são os próximos. Se vários filhos tiverem um valor false, eles serão classificados lexicograficamente pela chave.
  3. Filhos com um valor true para a chave filha especificada são os próximos. Se vários filhos tiverem um valor true, eles serão classificados lexicograficamente pela chave.
  4. Filhos com um valor numérico são os próximos, classificados em ordem crescente. Se vários filhos tiverem o mesmo valor numérico para o nó filho especificado, eles serão classificados por chave.
  5. Strings vêm depois dos números e são classificadas lexicograficamente em ordem crescente. Se vários filhos tiverem o mesmo valor para o nó filho especificado, eles serão ordenados lexicograficamente por chave.
  6. Objetos vêm por último e são classificados lexicograficamente pela chave em ordem crescente.

Remover listeners

Os observadores não interrompem automaticamente a sincronização de dados quando você sai de um ViewController. Se um observador não for removido corretamente, ele continuará sincronizando dados com a memória local e manterá quaisquer objetos capturados no manipulador de eventos, o que pode causar vazamentos de memória. Quando um observador não for mais necessário, remova-o ao transmitir o FIRDatabaseHandle associado ao método removeObserverWithHandle.

Ao adicionar um bloco de retorno de chamada a uma referência, um FIRDatabaseHandle é retornado. Esses handles podem ser usados para remover esse bloco.

Se vários listeners são adicionados a uma referência de banco de dados, cada um é chamado quando um evento é acionado. Para interromper a sincronização de dados nesse local, remova todos os observadores em um local chamando o método removeAllObservers.

Chamar removeObserverWithHandle ou removeAllObservers em um listener não remove automaticamente os listeners registrados nos nós filhos. É preciso também encontrar essas referências ou identificadores para removê-los.

Próximas etapas