Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Trabalhar com listas de dados no Android

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Este documento aborda o trabalho com listas de dados no Firebase. Para aprender os fundamentos da leitura e gravação de dados do Firebase, consulte Ler e gravar dados no Android .

Obter uma referência de banco de dados

Para ler e gravar dados do banco de dados, você precisa de uma instância de DatabaseReference :

Kotlin+KTX

private lateinit var database: DatabaseReference
// ...
database = Firebase.database.reference

Java

private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();

Ler e escrever listas

Anexar a uma lista de dados

Use o método push() para anexar dados a uma lista em aplicativos multiusuário. O método push() gera uma chave exclusiva sempre que um novo filho é adicionado à referência do Firebase especificada. Usando essas chaves geradas automaticamente para cada novo elemento na lista, vários clientes podem adicionar filhos ao mesmo local ao mesmo tempo sem conflitos de gravação. A chave exclusiva gerada por push() é baseada em um carimbo de data/hora, portanto, os itens da lista são automaticamente ordenados em ordem cronológica.

Você pode usar a referência aos novos dados retornados pelo método push() para obter o valor da chave gerada automaticamente pelo filho ou definir dados para o filho. Chamar getKey() em uma referência push() retorna o valor da chave gerada automaticamente.

Você pode usar essas chaves geradas automaticamente para simplificar o achatamento de sua estrutura de dados. Para obter mais informações, consulte o exemplo de fan-out de dados.

Ouvir eventos filhos

Ao trabalhar com listas, seu aplicativo deve escutar eventos filho em vez de eventos de valor usados ​​para objetos únicos.

Os eventos filho são acionados em resposta a operações específicas que acontecem com os filhos de um nó de uma operação, como um novo filho adicionado por meio do método push() ou um filho sendo atualizado por meio do método updateChildren() . Cada um deles juntos pode ser útil para ouvir alterações em um nó específico em um banco de dados.

Para ouvir eventos filho em DatabaseReference , anexe um ChildEventListener :

Ouvinte Retorno de chamada do evento Uso típico
ChildEventListener onChildAdded() Recupere listas de itens ou ouça adições a uma lista de itens. Esse retorno de chamada é acionado uma vez para cada filho existente e novamente sempre que um novo filho é adicionado ao caminho especificado. O DataSnapshot passado para o ouvinte contém os dados do novo filho.
onChildChanged() Ouça as alterações nos itens de uma lista. Este evento é disparado sempre que um nó filho é modificado, incluindo quaisquer modificações nos descendentes do nó filho. O DataSnapshot passado para o ouvinte de evento contém os dados atualizados para o filho.
onChildRemoved() Ouça os itens sendo removidos de uma lista. O DataSnapshot passado para o retorno de chamada do evento contém os dados do filho removido.
onChildMoved() Ouça as alterações na ordem dos itens em uma lista ordenada. Este evento é acionado sempre que o callback onChildChanged() é acionado por uma atualização que causa o reordenamento do filho. Ele é usado com dados ordenados com orderByChild ou orderByValue .

Por exemplo, um aplicativo de blog social pode usar esses métodos juntos para monitorar a atividade nos comentários de uma postagem, conforme mostrado abaixo:

Kotlin+KTX

val childEventListener = object : ChildEventListener {
    override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!)

        // A new comment has been added, add it to the displayed list
        val comment = dataSnapshot.getValue<Comment>()

        // ...
    }

    override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildChanged: ${dataSnapshot.key}")

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        val newComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildRemoved(dataSnapshot: DataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!)

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!)

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        val movedComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onCancelled(databaseError: DatabaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException())
        Toast.makeText(context, "Failed to load comments.",
                Toast.LENGTH_SHORT).show()
    }
}
databaseReference.addChildEventListener(childEventListener)

Java

ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());

        // A new comment has been added, add it to the displayed list
        Comment comment = dataSnapshot.getValue(Comment.class);

        // ...
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        Comment newComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        Comment movedComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException());
        Toast.makeText(mContext, "Failed to load comments.",
                Toast.LENGTH_SHORT).show();
    }
};
databaseReference.addChildEventListener(childEventListener);

Ouça eventos de valor

Embora usar um ChildEventListener seja a maneira recomendada de ler listas de dados, há situações em que anexar um ValueEventListener a uma referência de lista é útil.

Anexar um ValueEventListener a uma lista de dados retornará toda a lista de dados como um único DataSnapshot , que você pode repetir para acessar filhos individuais.

Mesmo quando há apenas uma única correspondência para a consulta, o instantâneo ainda é uma lista; ele contém apenas um único item. Para acessar o item, você precisa fazer um loop sobre o resultado:

Kotlin+KTX

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})

Java

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});

Esse padrão pode ser útil quando você deseja buscar todos os filhos de uma lista em uma única operação, em vez de ouvir eventos onChildAdded adicionais.

Desanexar ouvintes

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

Se um ouvinte tiver sido adicionado várias vezes a um local de dados, ele será chamado várias vezes para cada evento e você deverá desanexá-lo o mesmo número de vezes para removê-lo completamente.

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

Classificando e filtrando dados

Você pode usar a classe Realtime Database Query para recuperar dados classificados por chave, por valor ou por valor de um filho. Você também pode filtrar o resultado classificado para um número específico de resultados ou um intervalo de chaves ou valores.

Classificar dados

Para recuperar dados classificados, comece especificando um dos métodos order-by para determinar como os resultados são ordenados:

Método Uso
orderByChild() Ordene os resultados pelo valor de uma chave filho especificada ou caminho filho aninhado.
orderByKey() Ordene os resultados por chaves filhas.
orderByValue() Ordene os resultados por valores filhos.

Você só pode usar um método de ordem por vez. Chamar um método order-by várias vezes na mesma consulta gera um erro.

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

Kotlin+KTX

// My top posts by number of stars
val myUserId = uid
val myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
    .orderByChild("starCount")

myTopPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

Java

// My top posts by number of stars
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
        .orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

Isso define uma consulta que, quando combinada com um ouvinte filho, sincroniza o cliente com as postagens do usuário a partir do caminho no banco de dados com base em seu ID de usuário, ordenado pelo número de estrelas que cada postagem recebeu. Essa técnica de usar IDs como chaves de índice é chamada de distribuição de dados, você pode ler mais sobre ela em Estruturar seu banco de dados.

A chamada para o método orderByChild() especifica a chave filha para ordenar os resultados. Nesse caso, as postagens são classificadas pelo valor de seu respectivo filho "starCount" . As consultas também podem ser ordenadas por filhos aninhados, caso você tenha dados parecidos 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",
  }
},

Neste exemplo, podemos ordenar nossos elementos de lista por valores aninhados sob a chave de metrics , especificando o caminho relativo para o filho aninhado em nossa chamada orderByChild() .

Kotlin+KTX

// Most viewed posts
val myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views")
myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

Java

// Most viewed posts
Query myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views");
myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

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

Filtrando dados

Para filtrar dados, você pode combinar qualquer um dos métodos limit ou range com um método order-by ao construir uma consulta.

Método Uso
limitToFirst() Define o número máximo de itens a serem retornados desde o início da lista ordenada de resultados.
limitToLast() Define o número máximo de itens a serem retornados do final da lista ordenada de resultados.
startAt() Retorna itens maiores ou iguais à chave ou valor especificado, dependendo do método de ordem escolhido.
startAfter() Retorna itens maiores que a chave ou valor especificado, dependendo do método de ordenação escolhido.
endAt() Retorna itens menores ou iguais à chave ou valor especificado, dependendo do método de ordenação escolhido.
endBefore() Retorna itens menores que a chave ou valor especificado, dependendo do método de ordem escolhido.
equalTo() Retorna itens iguais à chave ou valor especificado, dependendo do método de ordem escolhido.

Ao contrário dos métodos de ordem, você pode combinar várias funções de limite ou intervalo. Por exemplo, você pode combinar os startAt() e endAt() para limitar os resultados a um intervalo de valores especificado.

Mesmo quando há apenas uma única correspondência para a consulta, o instantâneo ainda é uma lista; ele contém apenas um único item. Para acessar o item, você precisa fazer um loop sobre o resultado:

Kotlin+KTX

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})

Java

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});

Limite o número de resultados

Você pode usar os limitToFirst() e limitToLast() para definir um número máximo de filhos a serem sincronizados para um determinado retorno de chamada. Por exemplo, se você usar limitToFirst() para definir um limite de 100, receberá inicialmente apenas até 100 retornos de chamada onChildAdded() . Se você tiver menos de 100 itens armazenados em seu banco de dados do Firebase, um retorno de chamada onChildAdded() acionado para cada item.

À medida que os itens mudam, você recebe callbacks onChildAdded() para itens que entram na consulta e callbacks onChildRemoved() para itens que saem dela para que o número total permaneça em 100.

O exemplo a seguir demonstra como o aplicativo de blogging de exemplo define uma consulta para recuperar uma lista das 100 postagens mais recentes de todos os usuários:

Kotlin+KTX

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys.
databaseReference.child("posts").limitToFirst(100)

Java

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
Query recentPostsQuery = databaseReference.child("posts")
        .limitToFirst(100);

Este exemplo apenas define uma consulta, para realmente sincronizar os dados, ela precisa ter um listener anexado.

Filtre por chave ou valor

Você pode usar startAt() , startAfter() , endAt() , endBefore() e equalTo() para escolher pontos de início, término e equivalência arbitrários para consultas. Isso pode ser útil para paginar dados ou localizar itens com filhos que tenham um valor específico.

Como os dados da consulta são ordenados

Esta seção explica como os dados são classificados por cada um dos métodos order-by na classe Query .

orderByChild

Ao usar orderByChild() , os dados que contêm a chave filha especificada são ordenados da seguinte forma:

  1. Os filhos com um valor null para a chave filha especificada vêm primeiro.
  2. Filhos com um valor false para a chave filha especificada vêm em seguida. Se vários filhos tiverem um valor false , eles serão classificados lexicograficamente por chave.
  3. Filhos com um valor true para a chave filha especificada vêm em seguida. Se vários filhos tiverem um valor true , eles serão classificados lexicograficamente por chave.
  4. Filhos com um valor numérico vêm em seguida, 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. As 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. Os objetos vêm por último e são classificados lexicograficamente por chave em ordem crescente.

orderByKey

Ao usar orderByKey() para classificar seus dados, os dados são retornados em ordem crescente por chave.

  1. Filhos com uma chave que pode ser analisada como um número inteiro de 32 bits vêm primeiro, classificados em ordem crescente.
  2. Filhos com um valor de string como chave vêm em seguida, classificados lexicograficamente em ordem crescente.

orderByValue

Ao usar orderByValue() , os filhos são ordenados por seu valor. Os critérios de ordenação são os mesmos de orderByChild() , exceto que o valor do nó é usado em vez do valor de uma chave filha especificada.

Próximos passos

,

Este documento aborda o trabalho com listas de dados no Firebase. Para aprender os fundamentos da leitura e gravação de dados do Firebase, consulte Ler e gravar dados no Android .

Obter uma referência de banco de dados

Para ler e gravar dados do banco de dados, você precisa de uma instância de DatabaseReference :

Kotlin+KTX

private lateinit var database: DatabaseReference
// ...
database = Firebase.database.reference

Java

private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();

Ler e escrever listas

Anexar a uma lista de dados

Use o método push() para anexar dados a uma lista em aplicativos multiusuário. O método push() gera uma chave exclusiva sempre que um novo filho é adicionado à referência do Firebase especificada. Usando essas chaves geradas automaticamente para cada novo elemento na lista, vários clientes podem adicionar filhos ao mesmo local ao mesmo tempo sem conflitos de gravação. A chave exclusiva gerada por push() é baseada em um carimbo de data/hora, portanto, os itens da lista são automaticamente ordenados em ordem cronológica.

Você pode usar a referência aos novos dados retornados pelo método push() para obter o valor da chave gerada automaticamente pelo filho ou definir dados para o filho. Chamar getKey() em uma referência push() retorna o valor da chave gerada automaticamente.

Você pode usar essas chaves geradas automaticamente para simplificar o achatamento de sua estrutura de dados. Para obter mais informações, consulte o exemplo de fan-out de dados.

Ouvir eventos filhos

Ao trabalhar com listas, seu aplicativo deve escutar eventos filho em vez de eventos de valor usados ​​para objetos únicos.

Os eventos filho são acionados em resposta a operações específicas que acontecem com os filhos de um nó de uma operação, como um novo filho adicionado por meio do método push() ou um filho sendo atualizado por meio do método updateChildren() . Cada um deles juntos pode ser útil para ouvir alterações em um nó específico em um banco de dados.

Para ouvir eventos filho em DatabaseReference , anexe um ChildEventListener :

Ouvinte Retorno de chamada do evento Uso típico
ChildEventListener onChildAdded() Recupere listas de itens ou ouça adições a uma lista de itens. Esse retorno de chamada é acionado uma vez para cada filho existente e novamente sempre que um novo filho é adicionado ao caminho especificado. O DataSnapshot passado para o ouvinte contém os dados do novo filho.
onChildChanged() Ouça as alterações nos itens de uma lista. Este evento é disparado sempre que um nó filho é modificado, incluindo quaisquer modificações nos descendentes do nó filho. O DataSnapshot passado para o ouvinte de evento contém os dados atualizados para o filho.
onChildRemoved() Ouça os itens sendo removidos de uma lista. O DataSnapshot passado para o retorno de chamada do evento contém os dados do filho removido.
onChildMoved() Ouça as alterações na ordem dos itens em uma lista ordenada. Este evento é acionado sempre que o callback onChildChanged() é acionado por uma atualização que causa o reordenamento do filho. Ele é usado com dados ordenados com orderByChild ou orderByValue .

Por exemplo, um aplicativo de blog social pode usar esses métodos juntos para monitorar a atividade nos comentários de uma postagem, conforme mostrado abaixo:

Kotlin+KTX

val childEventListener = object : ChildEventListener {
    override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!)

        // A new comment has been added, add it to the displayed list
        val comment = dataSnapshot.getValue<Comment>()

        // ...
    }

    override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildChanged: ${dataSnapshot.key}")

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        val newComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildRemoved(dataSnapshot: DataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!)

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!)

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        val movedComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onCancelled(databaseError: DatabaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException())
        Toast.makeText(context, "Failed to load comments.",
                Toast.LENGTH_SHORT).show()
    }
}
databaseReference.addChildEventListener(childEventListener)

Java

ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());

        // A new comment has been added, add it to the displayed list
        Comment comment = dataSnapshot.getValue(Comment.class);

        // ...
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        Comment newComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        Comment movedComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException());
        Toast.makeText(mContext, "Failed to load comments.",
                Toast.LENGTH_SHORT).show();
    }
};
databaseReference.addChildEventListener(childEventListener);

Ouça eventos de valor

Embora usar um ChildEventListener seja a maneira recomendada de ler listas de dados, há situações em que anexar um ValueEventListener a uma referência de lista é útil.

Anexar um ValueEventListener a uma lista de dados retornará toda a lista de dados como um único DataSnapshot , que você pode repetir para acessar filhos individuais.

Mesmo quando há apenas uma única correspondência para a consulta, o instantâneo ainda é uma lista; ele contém apenas um único item. Para acessar o item, você precisa fazer um loop sobre o resultado:

Kotlin+KTX

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})

Java

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});

Esse padrão pode ser útil quando você deseja buscar todos os filhos de uma lista em uma única operação, em vez de ouvir eventos onChildAdded adicionais.

Desanexar ouvintes

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

Se um ouvinte tiver sido adicionado várias vezes a um local de dados, ele será chamado várias vezes para cada evento e você deverá desanexá-lo o mesmo número de vezes para removê-lo completamente.

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

Classificando e filtrando dados

Você pode usar a classe Realtime Database Query para recuperar dados classificados por chave, por valor ou por valor de um filho. Você também pode filtrar o resultado classificado para um número específico de resultados ou um intervalo de chaves ou valores.

Classificar dados

Para recuperar dados classificados, comece especificando um dos métodos order-by para determinar como os resultados são ordenados:

Método Uso
orderByChild() Ordene os resultados pelo valor de uma chave filho especificada ou caminho filho aninhado.
orderByKey() Ordene os resultados por chaves filhas.
orderByValue() Ordene os resultados por valores filhos.

Você só pode usar um método de ordem por vez. Chamar um método order-by várias vezes na mesma consulta gera um erro.

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

Kotlin+KTX

// My top posts by number of stars
val myUserId = uid
val myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
    .orderByChild("starCount")

myTopPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

Java

// My top posts by number of stars
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
        .orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

Isso define uma consulta que, quando combinada com um ouvinte filho, sincroniza o cliente com as postagens do usuário a partir do caminho no banco de dados com base em seu ID de usuário, ordenado pelo número de estrelas que cada postagem recebeu. Essa técnica de usar IDs como chaves de índice é chamada de distribuição de dados, você pode ler mais sobre ela em Estruturar seu banco de dados.

A chamada para o método orderByChild() especifica a chave filha para ordenar os resultados. Nesse caso, as postagens são classificadas pelo valor de seu respectivo filho "starCount" . As consultas também podem ser ordenadas por filhos aninhados, caso você tenha dados parecidos 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",
  }
},

Neste exemplo, podemos ordenar nossos elementos de lista por valores aninhados sob a chave de metrics , especificando o caminho relativo para o filho aninhado em nossa chamada orderByChild() .

Kotlin+KTX

// Most viewed posts
val myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views")
myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})

Java

// Most viewed posts
Query myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views");
myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});

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

Filtrando dados

Para filtrar dados, você pode combinar qualquer um dos métodos limit ou range com um método order-by ao construir uma consulta.

Método Uso
limitToFirst() Define o número máximo de itens a serem retornados desde o início da lista ordenada de resultados.
limitToLast() Define o número máximo de itens a serem retornados do final da lista ordenada de resultados.
startAt() Retorna itens maiores ou iguais à chave ou valor especificado, dependendo do método de ordem escolhido.
startAfter() Retorna itens maiores que a chave ou valor especificado, dependendo do método de ordenação escolhido.
endAt() Retorna itens menores ou iguais à chave ou valor especificado, dependendo do método de ordenação escolhido.
endBefore() Retorna itens menores que a chave ou valor especificado, dependendo do método de ordem escolhido.
equalTo() Retorna itens iguais à chave ou valor especificado, dependendo do método de ordem escolhido.

Ao contrário dos métodos de ordem, você pode combinar várias funções de limite ou intervalo. Por exemplo, você pode combinar os startAt() e endAt() para limitar os resultados a um intervalo de valores especificado.

Mesmo quando há apenas uma única correspondência para a consulta, o instantâneo ainda é uma lista; ele contém apenas um único item. Para acessar o item, você precisa fazer um loop sobre o resultado:

Kotlin+KTX

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})

Java

// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});

Limite o número de resultados

Você pode usar os limitToFirst() e limitToLast() para definir um número máximo de filhos a serem sincronizados para um determinado retorno de chamada. Por exemplo, se você usar limitToFirst() para definir um limite de 100, receberá inicialmente apenas até 100 retornos de chamada onChildAdded() . Se você tiver menos de 100 itens armazenados em seu banco de dados do Firebase, um retorno de chamada onChildAdded() acionado para cada item.

À medida que os itens mudam, você recebe callbacks onChildAdded() para itens que entram na consulta e callbacks onChildRemoved() para itens que saem dela para que o número total permaneça em 100.

O exemplo a seguir demonstra como o aplicativo de blogging de exemplo define uma consulta para recuperar uma lista das 100 postagens mais recentes de todos os usuários:

Kotlin+KTX

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys.
databaseReference.child("posts").limitToFirst(100)

Java

// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
Query recentPostsQuery = databaseReference.child("posts")
        .limitToFirst(100);

Este exemplo apenas define uma consulta, para realmente sincronizar os dados, ela precisa ter um listener anexado.

Filtre por chave ou valor

Você pode usar startAt() , startAfter() , endAt() , endBefore() e equalTo() para escolher pontos de início, término e equivalência arbitrários para consultas. Isso pode ser útil para paginar dados ou localizar itens com filhos que tenham um valor específico.

Como os dados da consulta são ordenados

Esta seção explica como os dados são classificados por cada um dos métodos order-by na classe Query .

orderByChild

Ao usar orderByChild() , os dados que contêm a chave filha especificada são ordenados da seguinte forma:

  1. Os filhos com um valor null para a chave filha especificada vêm primeiro.
  2. Filhos com um valor false para a chave filha especificada vêm em seguida. Se vários filhos tiverem um valor false , eles serão classificados lexicograficamente por chave.
  3. Filhos com um valor true para a chave filha especificada vêm em seguida. Se vários filhos tiverem um valor true , eles serão classificados lexicograficamente por chave.
  4. Filhos com um valor numérico vêm em seguida, 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. As 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. Os objetos vêm por último e são classificados lexicograficamente por chave em ordem crescente.

orderByKey

Ao usar orderByKey() para classificar seus dados, os dados são retornados em ordem crescente por chave.

  1. Filhos com uma chave que pode ser analisada como um número inteiro de 32 bits vêm primeiro, classificados em ordem crescente.
  2. Filhos com um valor de string como chave vêm em seguida, classificados lexicograficamente em ordem crescente.

orderByValue

Ao usar orderByValue() , os filhos são ordenados por seu valor. Os critérios de ordenação são os mesmos de orderByChild() , exceto que o valor do nó é usado em vez do valor de uma chave filha especificada.

Próximos passos