Principais diferenças entre consultas sql e nosql no Firebase

Em:

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.

nosql-expert

Será algo bem prático, não entrarei em detalhes, pois acho que não serão necessários… não agora.

Tabela usuario

-----------------------------------------------------------------------------------------
|Id  |Nome      |Sobrenome    |email                    |idade  |cidade          |estado|
|----|----------|-------------|-------------------------|-------|----------------|------|
|  1 | Evelyn   | Mendes      | [email protected]    |    35 | Porto Alegre   |RS    |
|  2 | John     | Doe         | [email protected]            |    20 | Rio de Janeiro |RJ    |
|  4 | Esmeralda| Silva       | [email protected]     |    44 | Florianópolis  |SC    |
|  5 | João     | Silva       | [email protected]          |    66 | Bagé           |RS    |
-----------------------------------------------------------------------------------------

Temos linhas e colunas bem definidas, tudo arrumadinho <3

Vamos ver como fica no firebase, vulgo JSON ;P

 {
    "usuario" : {
        "1" :{
            "nome" : "Evelyn",
            "sobrenome" : "Mendes",
            "email": "[email protected]",
            "idade" : 35,
            "cidade":  "Porto Alegre",
            "estado" : "RS"
        },
        "2":{
            "nome" : "Jonh",
            "sobrenome" : "Doe",
            "email": "[email protected]",
            "idade" : 20,
            "cidade":  "Rio de Janeiro",
            "estado" : "RS"
        },
        "4":{
            "nome" : "Esmeralda",
            "sobrenome" : "Silva",
            "email": "[email protected]",
            "idade" : 44,
            "cidade":  "Florianópolis",
            "estado" : "SC"
        },
        "5":{
            "nome" : "João",
            "sobrenome" : "Silva",
            "email": "[email protected]",
            "idade" : 66,
            "cidade":  "Bagé",
            "estado" : "RS"
        }
    }
}

Afe, que bagunça kkk!!!

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. screen-shot-2017-09-22-at-21-50-30 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  |email                  |idade  |cidade          |estado|
|----|----------|-----------|-----------------------|-------|----------------|------|
|  1 | Evelyn   | Mendes    | [email protected]  |    35 | Porto Alegre   |RS    |
------------------------------------------------------------------------------------- 

Firebase

const usuarioRef = rootRef.child('usuario').child('1');
Resultado
"1" :{
    "nome" : "Evelyn",
    "sobrenome" : "Mendes",
    "email": "[email protected]",
    "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    |email         |idade  |cidade          |estado|
|----|----------|-------------|--------------|-------|----------------|------|
|  2 | John     | Doe         | [email protected] |    20 | Rio de Janeiro |RJ    |
------------------------------------------------------------------------------

Firebase

const nomeRef = rootRef.child('usuario')
                       .orderByChild('nome')
                       .equalTo('John');
Resultado
"2":{
   "nome" : "Jonh",
   "sobrenome" : "Doe",
   "email": "[email protected]",
   "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    |email                  |idade  |cidade          |estado|
|----|----------|-------------|-----------------------|-------|----------------|------|
|  1 | Evelyn   | Mendes      | [email protected]  |    35 | Porto Alegre   |RS    |
|  2 | John     | Doe         | [email protected]          |    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": "[email protected]",
    "idade" : 35,
    "cidade":  "Porto Alegre",
    "estado" : "RS"
},
"2":{
    "nome" : "Jonh",
    "sobrenome" : "Doe",
    "email": "[email protected]",
    "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  |email                  |idade  |cidade          |estado|
|----|----------|-----------|-----------------------|-------|----------------|------|
|  1 | Evelyn   | Mendes    | [email protected]  |    35 | Porto Alegre   |RS    |
|  4 | Esmeralda| Silva     | [email protected]   |    44 | Florianópolis  |SC    |
-------------------------------------------------------------------------------------

Firebase

const startERef = rootRef.child('usuario')
                         .orderByChild('nome')
                         .startAt('E');
resultado 
"1" :{
    "nome" : "Evelyn",
    "sobrenome" : "Mendes",
    "email": "[email protected]",
    "idade" : 35,
    "cidade":  "Porto Alegre",
    "estado" : "RS"
}, 
"4":{
    "nome" : "Esmeralda",
    "sobrenome" : "Silva",
    "email": "[email protected]",
    "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    |email                  |idade  |cidade          |estado|
|----|----------|-------------|-----------------------|-------|----------------|------|
|  1 | Evelyn   | Mendes      | [email protected]  |    35 | Porto Alegre   |RS    |
|  2 | John     | Doe         | [email protected]          |    20 | Rio de Janeiro |RJ    |
|  4 | Esmeralda| Silva       | [email protected]   |    44 | Florianópolis  |SC    |
---------------------------------------------------------------------------------------

Firebase

const idade50Ref = rootRef.child('usuario')
                          .orderByChild('idade')
                          .endAt(49);
resultado
"1" :{
    "nome" : "Evelyn",
    "sobrenome" : "Mendes",
    "email": "[email protected]",
    "idade" : 35,
    "cidade":  "Porto Alegre",
    "estado" : "RS"
},
"2":{
    "nome" : "Jonh",
    "sobrenome" : "Doe",
    "email": "[email protected]",
    "idade" : 20,
    "cidade":  "Rio de Janeiro",
    "estado" : "RS"
},
"4":{
    "nome" : "Esmeralda",
    "sobrenome" : "Silva",
    "email": "[email protected]",
    "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    |email           |idade  |cidade    |estado|
|----|----------|-------------|----------------|-------|----------|------|
|  5 | João     | Silva       | [email protected] |    66 | Bagé     |RS    |
--------------------------------------------------------------------------

Firebase

const idadeRef = rootRef.child('usuario')
                        .orderByChild('idade')
                        .startAt(51);
resultado  
"5":{
    "nome" : "João",
    "sobrenome" : "Silva",
    "email": "[email protected]",
    "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    |email                 |idade  |cidade          |estado|
|----|----------|-------------|----------------------|-------|----------------|------|
|  1 | Evelyn   | Mendes      | [email protected]nsnerd.com |    35 | Porto Alegre   |RS    |
|  4 | Esmeralda| Silva       | [email protected]  |    44 | Florianópolis  |SC    |
--------------------------------------------------------------------------------------  

Firebase

const idadesRef = rootRef.child('usuario')
                         .orderByChild('idade')
                         .startAt(21)
                         .endAt(50);
resultado
"1" :{
    "nome" : "Evelyn",
    "sobrenome" : "Mendes",
    "email": "[email protected]",
    "idade" : 35,
    "cidade":  "Porto Alegre",
    "estado" : "RS"
}
"4":{
    "nome" : "Esmeralda",
    "sobrenome" : "Silva",
    "email": "[email protected]",
    "idade" : 44,
    "cidade":  "Florianópolis",
    "estado" : "SC"
} 

8 -Vamos complicar um pouco as coisas?

Vamos selecionar todos os usuários que tem 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    |email           |idade  |cidade  |estado|
|----|----------|-------------|----------------|-------|--------|------|
|  5 | João     | Silva       | [email protected] |    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… But……….

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… oops!

Miga sua louca, como vamos resolver isso?
Calma, calma, pra tudo tem um jeito!!

Na realidade, uma das premissas de uma base nosql como o firebase é pensar na forma que vc irá pesquisar ao inputar dados. Vamos fazer uma modificação no json e vc 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 vc 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": "[email protected]",
   "idade" : 66,
   "cidade":  "Bagé",
   "estado" : "RS",
   "idade_estado" : "66_RS"
}

9 – Agora digamos que além da idade e do estado, eu tb 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    |email            |idade  |cidade     |estado|
|----|----------|-------------|-----------------|-------|-----------|------|
|  5 | João     | Silva       | [email protected]  |    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 3 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 vc digita 66, vc procura por quem mora no estado do Rio Grande do sul, então vc escolhe RS no campo select e além disso, vc quer todos os nomes que comecem por J, Jo, Joã, João, até enJoar. 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 idade já estará no valor, estado também, a função startAt() irá trabalhar será somente o nome conforme for sendo pesquisado, ficaria algo 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": "[email protected]",
    "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, com muitos registros. Outra questão é o unicode que deve ser levado em consideração nas pesquisas por texto. A 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 aonde 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.


Gentem, muito obrigada, no próximo artigo irei falar sobre regras(rules para os mais íntimos) da base de dados, vcs irão se surpreender com o poder que o firebase oferece para validações, tipagens, e pasmem, até “FKs”, simmm tem, mas reparem que é entre aspas rsrs

Bejussss

Patrocinadores BrazilJS

Gold

Silver

Bronze

Apoio

BrazilJS® é uma iniciativa NASC.     Hosted by Getup