O objetivo desse artigo é mostrar ao programador t-SQL, pl-SQL ou desenvolvedores em geral, como são feitas as consultas básicas numa base de dados NoSQL, mais especificamente o Firebase.

Será algo bem prático. Não entrarei em detalhes, pois acho que não serão necessários. Pelo menos não agora.
Tabela usuário
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 1 | Evelyn | Mendes | evelyn@transnerd.com | 35 | Porto Alegre | RS |
| 2 | John | Doe | john@doe.com | 20 | Rio de Janeiro | RJ |
| 3 | Esmeralda | Silva | esmeralda@email.com | 44 | Florianópolis | SC |
| 4 | João | Silva | joao@email.com | 66 | Bagé | RS |
Temos linhas e colunas bem definidas, tudo arrumadinho.
Vamos ver como fica no Firebase, vulgo json.
{
"usuario" : {
"1" :{
"nome" : "Evelyn",
"sobrenome" : "Mendes",
"email": "evelyn@transnerd.com",
"idade" : 35,
"cidade": "Porto Alegre",
"estado" : "RS"
},
"2":{
"nome" : "Jonh",
"sobrenome" : "Doe",
"email": "jonh@email.com",
"idade" : 20,
"cidade": "Rio de Janeiro",
"estado" : "RS"
},
"4":{
"nome" : "Esmeralda",
"sobrenome" : "Silva",
"email": "esmeralda@email.com",
"idade" : 44,
"cidade": "Florianópolis",
"estado" : "SC"
},
"5":{
"nome" : "João",
"sobrenome" : "Silva",
"email": "joao@email.com",
"idade" : 66,
"cidade": "Bagé",
"estado" : "RS"
}
}
}
Que bagunça!
Dentro desses dois contextos, vamos agora começar a fazer nossas consultas.
Obs: Irei supor que todas as configurações do Firebase de acesso e de referência raiz já estejam definidas como o “rootref”: const rootref = firebase.database().ref(); o que chamamos de root, é o que o Firebase entende por documento raiz.

Na imagem root, é “diversidade-6d120”. Tudo abaixo dele são os registros que serão utilizados, como o nó/tabela palavras.
1 – Recuperar um registro de um usuário pelo seu id
SQL
SELECT * FROM usuario WHERE id = 1;
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 1 | Evelyn | Mendes | evelyn@transnerd.com | 35 | Porto Alegre | RS |
Firebase
const usuarioRef = rootRef.child('usuario').child('1');
Resultado
"1" :{
"nome" : "Evelyn",
"sobrenome" : "Mendes",
"email": "evelyn@transnerd.com",
"idade" : 35,
"cidade": "Porto Alegre",
"estado" : "RS"
}
2 – Recuperar um usuario pelo seu nome
SQL
select * from usuario where nome = 'John';
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 2 | John | Doe | john@doe.com | 20 | Rio de Janeiro | RJ |
Firebase
const nomeRef = rootRef.child('usuario')
.orderByChild('nome')
.equalTo('John');
Resultado
"2":{
"nome" : "Jonh",
"sobrenome" : "Doe",
"email": "jonh@email.com",
"idade" : 20,
"cidade": "Rio de Janeiro",
"estado" : "RS"
}
3 – Limitar a quantidade de registros que devem retornar em 2
SQL
select top 2 * from usuario --ou select * from usuario limit 2 --Obs: eu prefiro limit, top é muito heterocisnormativo, blergh!!
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 1 | Evelyn | Mendes | evelyn@transnerd.com | 35 | Porto Alegre | RS |
| 2 | John | Doe | john@doe.com | 20 | Rio de Janeiro | RJ |
Firebase
const limitRef = rootRef.child('usuario').limitToFirst(2);
//firebase usa limit, não usa top. Muito amor
Resultado
"1" :{
"nome" : "Evelyn",
"sobrenome" : "Mendes",
"email": "evelyn@transnerd.com",
"idade" : 35,
"cidade": "Porto Alegre",
"estado" : "RS"
},
"2":{
"nome" : "Jonh",
"sobrenome" : "Doe",
"email": "jonh@email.com",
"idade" : 20,
"cidade": "Rio de Janeiro",
"estado" : "RS"
}
4 – Pesquisar os usuarios aonde o nome comece com a letra e
SQL
select * from usuario where nome like 'E%';
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 1 | Evelyn | Mendes | evelyn@transnerd.com | 35 | Porto Alegre | RS |
| 4 | Esmeralda | Silva | esmeralda@email.com | 44 | Florianópolis | SC |
Firebase
const startERef = rootRef.child('usuario')
.orderByChild('nome')
.startAt('E');
Resultado
"1" :{
"nome" : "Evelyn",
"sobrenome" : "Mendes",
"email": "evelyn@transnerd.com",
"idade" : 35,
"cidade": "Porto Alegre",
"estado" : "RS"
},
"4":{
"nome" : "Esmeralda",
"sobrenome" : "Silva",
"email": "esmeralda@email.com",
"idade" : 44,
"cidade": "Florianópolis",
"estado" : "SC"
}
5 – Pesquisar os usuários que tem idade menor que 50 anos
SQL
select * from usuario where idade < 50;
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 1 | Evelyn | Mendes | evelyn@transnerd.com | 35 | Porto Alegre | RS |
| 2 | John | Doe | john@doe.com | 20 | Rio de Janeiro | RJ |
| 4 | Esmeralda | Silva | esmeralda@email.com | 44 | Florianópolis | SC |
Firebase
const idade50Ref = rootRef.child('usuario')
.orderByChild('idade')
.endAt(49);
Resultado
"1" :{
"nome" : "Evelyn",
"sobrenome" : "Mendes",
"email": "evelyn@transnerd.com.br",
"idade" : 35,
"cidade": "Porto Alegre",
"estado" : "RS"
},
"2":{
"nome" : "Jonh",
"sobrenome" : "Doe",
"email": "jonh@email.com",
"idade" : 20,
"cidade": "Rio de Janeiro",
"estado" : "RS"
},
"4":{
"nome" : "Esmeralda",
"sobrenome" : "Silva",
"email": "esmeralda@email.com",
"idade" : 44,
"cidade": "Florianópolis",
"estado" : "SC"
}
6 – Pesquisar os usuários que tem idade maior que 50 anos
SQL
select * from usuario where idade > 50;
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 5 | João | Silva | joao@email.com | 66 | Bagé | RS |
Firebase
const idadeRef = rootRef.child('usuario')
.orderByChild('idade')
.startAt(51);
Resultado
"5":{
"nome" : "João",
"sobrenome" : "Silva",
"email": "joao@email.com",
"idade" : 66,
"cidade": "Bagé",
"estado" : "RS"
}
7 – Agora vamos pesquisar os usuários que tem idade entre 21 e 50 anos
SQL
select * from usuario where idade >= 21 and idade <=50;
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 1 | Evelyn | Mendes | evelyn@transnerd.com | 35 | Porto Alegre | RS |
| 4 | Esmeralda | Silva | esmeralda@email.com | 44 | Florianópolis | SC |
Firebase
const idadesRef = rootRef.child('usuario')
.orderByChild('idade')
.startAt(21)
.endAt(50);
Resultado
"1" :{
"nome" : "Evelyn",
"sobrenome" : "Mendes",
"email": "evelyn@transnerd.com",
"idade" : 35,
"cidade": "Porto Alegre",
"estado" : "RS"
}
"4":{
"nome" : "Esmeralda",
"sobrenome" : "Silva",
"email": "esmeralda@email.com",
"idade" : 44,
"cidade": "Florianópolis",
"estado" : "SC"
}
8 -Vamos complicar um pouco as coisas?
Vamos selecionar todos os usuários que têm 66 anos e moram no estado RS. No SQL é fácil.
SQL
select * from usuario where idade = 66 and estado ='RS';
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 5 | João | Silva | joao@email.com | 66 | Bagé | RS |
Como eu havia dito, no sql é facil ,e no firebase?
Vamos tentar. Parece fácil, né? Apenas adicionar mais e mais orders e equals. Porém:
const erroRef = rootRef.child('usuario')
.orderByChild('idade').equalTo(66)
.orderByChild('estado').equalTo('RS')
Porém, isso dará um erro, pois o Firebase só aceita uma função de ordenação por instrução. Ops.
Como vamos resolver isso?
Calma. Pra tudo tem um jeito!
Na realidade, uma das premissas de uma base NoSQL como o Firebase, é pensar na forma que você irá pesquisar ao imputar dados. Vamos fazer uma modificação no json e você entenderá. Insira essa chave no registro 5:
"idade_estado" : "66_RS"
Note que foi inserida uma nova chave concatenando dois valores, idade e estado. Isso você pode fazer usando o Firebase Functions, a cada iteração de insert e update na base de dados. Feito isso a instrução ficará simplificada.
Firebase
const idadeEstadoRef = rootRef.child('usuario')
.orderByChild('idade_estado')
.equalTo('66_RS');
Resultado
"5":{
"nome" : "João",
"sobrenome" : "Silva",
"email": "joao@email.com",
"idade" : 66,
"cidade": "Bagé",
"estado" : "RS",
"idade_estado" : "66_RS"
}
9 – Agora digamos que além da idade e do estado, eu também quero pesquisar pelo nome do usuário, mas de forma incremental
Novamente no SQL, é fácil.
SQL
select * from usuario where idade = 66 and estado ='RS' and nome like 'Jo%';
Resultado
| Id | Nome | Sobrenome | Idade | Cidade | Estado | |
| 5 | João | Silva | joao@email.com | 66 | Bagé | RS |
E agora no Firebase?
Vamos começar aproveitando o que fizemos no registro 5 e acrescentar uma nova chave.
"idade_estado_nome" : "66_RS_João Silva"
Imagine três campos; Um input de idade, um select de estado e um input de nome. Você quer a idade de 66 anos, então no campo idade, você digita 66, procura por quem mora no estado do Rio Grande do Sul, e então escolhe RS no campo select. E além disso, você quer todos os nomes que comecem por J, Jo, Joã, João. Vamos criar uma variável para ficar mais descritivo. A forma como estou escrevendo é meramente ilustrativa.
let idade_estado_nome = idade.value + '-' + estado.value + '-' + nome.value;
const idadeEstadoNomeRef = rootRef.child('usuario')
.orderByChild('idade_estado_nome')
.startAt(idade_estado_nome);
Note que idade já estará no valor e estado também. A função startAt() que irá trabalhar será somente o nome conforme for sendo pesquisado. Ficaria algo assim:
const idadeEstadoNomeRef = rootRef.child('usuario')
.orderByChild('idade_estado_nome')
.startAt('66_RS_J');
//----------------------------------------------------------------
const idadeEstadoNomeRef = rootRef.child('usuario')
.orderByChild('idade_estado_nome')
.startAt('66_RS_Jo');
//----------------------------------------------------------------
const idadeEstadoNomeRef = rootRef.child('usuario')
.orderByChild('idade_estado_nome')
.startAt('66_RS_Joã');
//----------------------------------------------------------------
const idadeEstadoNomeRef = rootRef.child('usuario')
.orderByChild('idade_estado_nome')
.startAt('66_RS_João');
Como temos apenas um João na nossa base de dados, o resultado será sempre o mesmo.
Resultado
"5":{
"nome" : "João",
"sobrenome" : "Silva",
"email": "joao@email.com",
"idade" : 66,
"cidade": "Bagé",
"estado" : "RS",
"idade_estado" : "66_RS",
"idade_estado_nome" : "66_RS_João Silva"
}
Ponto de alerta: Eu não sei o custo que isso irá ter para o Firebase em bases muito grandes e com muitos registros. Outra questão é o unicode, que deve ser levado em consideração nas pesquisas por texto. À primeira vista parece que não se pode fazer muita coisa no Firebase, não se tem joins bem declarados, por exemplo, mas você tende a não precisar deles e demais funcionalidades de bancos relacionais, pois além do conceito de chaves compostas, ainda temos a desnormalização, onde os dados são replicados. Um exemplo seria um usuário inteiro, não somente seu uid estar dentro de registros de eventos que ele participará, e também estar dentro de registros de reuniões para esse usuário. Isso é normal e plenamente aceito no Firebase.
Gente, muito obrigada. No próximo artigo irei falar sobre regras (rules) da base de dados. Vocês irão se surpreender com o poder que o Firebase oferece para validações, tipagens, e pasmem, até “FKs”. Sim, tem. Porém, reparem que é entre aspas.
Beijos!



