Como utilizar o Firebase com Flutter — FlutterFire (Part 5)
Cloud Firestore
A necessidade por opções de base de dados com maior performance e flexibilidade no consumo e gestão de dados levou aos engenheiros da Google a pensar numa solução à altura de tais requisitos. É então que temos o Cloud Firestore, uma evolução do Realtime Database, que é igualmente NoSQL parte do Firebase.
Este artigo é parte de uma série de artigos relacionados ao FlutterFire que conta com os seguintes artigos:
- Como utilizar o Firebase com Flutter (Introdução — Configurando o FlutterFire)
- Como utilizar o Firebase com Flutter (FlutterFire Auth — Email/Password)
- Como utilizar o Firebase com Flutter (FlutterFire Auth — Phone)
- Como utilizar o Firebase com Flutter (FlutterFire Auth — Social(Google))
- Como utilizar o Firebase com Flutter (Cloud Firestore)(este artigo)
Cloud Firestore
Cloud Firestore é uma base de dados do tipo NoSQL assíncrona baseada em cloud que permite realizar operações de forma bastante flexível e que oferece suporte para trabalhar com dados em modo offline com base em streams.
Para colocar o cloud firestore em funcionamento em nossa aplicação é necessário adicionar a dependência ao nosso pubspec.yaml.
cloud_firestore: ^0.16.0+1
O cloud firestore possibilita realizar todas as operações de CRUD de forma bem simplificada, assim como pôde-se observar com as funções de autenticação, contudo, aqui iremos observar a criação, inserção de dados e efectuar uma query.
Mas antes, é importante notar que para o Android pode se dar o caso de enfrentar o erro de multiDex após algumas interações, podendo resolver adicionando
multiDexEnabled true
ao android/app/src/build.gradle>defaultConfig e
implementation 'com.android.support:multidex:1.0.3'
ao android/app/src/build.gradle>dependencies
1. Criar base de dados
Antes que se comece a realizar as operações de CRUD é necessário criar a base de dados pela consola do nosso projecto firebase no menu Cloud Firestore.
2. Inserir dados
Primeiro é importante notar que para inserir documentos (dados) em um primeira tabela não precisa de uma instrução inicial para criar a mesma, até porque não lidamos com tabelas mas sim com coleções e basta apenas referenciar a coleção que pretendemos usar e caso a mesma não exista o firebase se responsabiliza por criar e adicionar o documento.
Future<String> addMinion(String minionName) {
//adicionar o objecto em forma de json para a coleção de minions
return minions
.add({
'nome': minionName,
})
.then((value) => "Mais um minion adicionado à família")
.catchError((error) =>
"Parece que teve problemas com o último minion:\n $error");
}
3. Efectuar query
Existe uma gama de queries que podem ser feitas com recurso ao firestore, desde comparações entre valores singulares, intervalos e em arrays com indicadores como isEqualTo, isGreaterThan, arrayContainsAny.
Para ilustração vamos ver o caso de um query que nos traz snapshot para o caso em que o nome é igual a um valor passado como argumento.
Future<QuerySnapshot> queryCollection(queryString) async {
//retorna o snapshot equivalente aos objectos json onde
// o nome é igual ao passado como argumento
return await minions.where('nome', isEqualTo: queryString).get();
}
4. Actualizar documento
Actualizar um documento é igualmente straight-forward como podemos ver para as implementações anteriores, bastando apenas:
doc(documentId).update({'nome': novoNome})
.then((value) => "Minion com nome actualizado")
.catchError((error) =>
"Oops, parece que não deu pra actualizar:\n $error");
Esta função é apenas útil se realmente conhecermos o documentId do documento em questão, o que geralmente não acontece, para actualizar baseado em um elemento mais prático de ter acesso podemos:
Future<QuerySnapshot> queryCollection(queryString) async {
//retorna o snapshot equivalente aos objectos json onde
// o nome é igual ao passado como argumento
return await minions.where('nome', isEqualTo: queryString).get();
}
Future updateUser(nome, novoNome) {
//com base na coleção pegamos todos os dados que nela existem, que retorna
//QuerySnapshot e usando o mesmo para iterar pelos documentos dentro dele
return minions.get().then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
//verificar se o dcumento tem como atributo nome igual ao pretendido alterar
if (doc['nome'] == nome) {
minions
.doc(doc.id)//pegar o id do documento que se pretende actualizar
.update({'nome': novoNome})
.then((value) => "Minion com nome actualizado")
.catchError((error) =>
"Oops, parece que não deu pra actualizar:\n $error");
}
});
});
}
5. Apagar documento
A ideia para apagar um documento em específico é a mesma que para a actualização, bastando apenas substituir o update pelo delete.
doc(documentId).delete()
.then((value) => "Minion $nome removido com sucesso")
.catchError((error) =>
"Oops, parece que não deu pra remover:\n $error");
Implementação
A nossa UI é algo como
Notemos que logo que a adição é concluída a UI actualiza sem precisar refrescar a página, isto porque está a se trabalhar com streams que permitem manter a lista sincronizada com o firestore em tempo real.
Nota: Este exemplo apenas implementa a inserção, não tendo a actualização e remoção.
O projecto já actualizado está disponível pelo github, espero que tire proveito do mesmo e contribua com melhorias em qualquer aspecto.
Espero que tenha aprendido com este artigo e que se tenha divertido enquanto lia.
Obrigado por acompanhar até ao fim e espero por você no próximo artigo.
Para questões e sugestões esteja a vontade para tal nos comentários, email igorlsambo1999@gmail.com ou twitter @lsambo02.
Obrigado e até ao próximo artigo!!!