DEV Community 👩‍💻👨‍💻

Rômulo Silva
Rômulo Silva

Posted on

Brincando com Ecto.Query

Introdução

Sejam bem-vindos, fico imensamente feliz com seu interesse em aprender um pouco mais sobre o Ecto e suas funcionalidades do modulo Ecto.Query para construir queries SQL

Vamos usar o projeto do post Introdução ao Ecto para brincarmos um pouco com as queries sql.

Recomendo ler o projeto anterior sobre Ecto para melhor compreensão.

Schemas utilizado para este projeto:

Módulo User

defmodule Ecto4noobs.User do
  use Ecto.Schema

  import Ecto.Changeset

  alias Ecto4noobs.Movie

  schema "users" do
    field(:name, :string)
    field(:email, :string)
    field(:age, :integer)

    belongs_to(:movie, Movie)
  end
end
Enter fullscreen mode Exit fullscreen mode

Módulo Movie

defmodule Ecto4noobs.Movie do
  use Ecto.Schema

  import Ecto.Changeset

  alias Ecto4noobs.User

  schema "movies" do
    field(:title, :string)
    field(:director, :string)
    field(:year, :integer)

    has_many(:users, User)
  end
end
Enter fullscreen mode Exit fullscreen mode

Relação Belongs To/Has Many

Vamos iniciar com dois schemas: User e Movie. Vamos implementar uma relação belongs_to/has_many entre os dois: Um filme tem vários (has many) usuários e um usuário pertence a (belongs to) um filme.

Schema Belongs To

Belongs To utiliza a chave estrangeira para tornar o filme associado a um usuário disponível quando executamos a consulta.

Schema Has Many

Has Many não adiciona dados ao banco de dados por si só. O que ela faz é utilizar uma chave estrangeira no schema associado (users).

Listando os filmes

from(m in Movie) |> Repo.all()
Enter fullscreen mode Exit fullscreen mode

Image description

Se notarmos, veremos que temos a seguinte mensagem: NotLoadAssociation. Caso a gente queria listar os usuários juntamente aos filmes, apenas essa query não é o suficiente.

Para carregas as associações, faremos:

query = from(m in Movie, preload: [:users]) |> Repo.all()
Enter fullscreen mode Exit fullscreen mode

Image description

Exemplos de query com filtros where:

Buscando os usuários com idade menos que 20.

query = from(u in User, where: u.age < 20)
Enter fullscreen mode Exit fullscreen mode

U representa uma linha da tabela User e em seguida a gente passa a condição que queremos filtrar, que no caso queremos filtrar a idade que for menor que 20.

Image description

Antes de continuarmos vamos aprender um pouco sobre SQL JOIN

O que é um JOIN?

Bom, o join combina duas tabelas através de alguma chave ou valor comum entre elas.

Existem alguns tipos diferentes de JOIN:

  • INNER JOIN: É um comando que permite a seleção de informações em diferentes tabelas, desde que a informação em questão seja compartilhada por ambas.

  • LEFT JOIN: É um comando que retorna todos os registros da tabela à esquerda e os registros correspondentes da tabela à direita.

  • RIGHT JOIN: Ao contrário do LEFT JOIN, o comando RIGHT JOIN retorna todos os dados encontrados na tabela à direita. Porém, se não tiver dados associados entre as tabelas esquerda e direita, ele retorna valores nulos.

Usando INNER JOIN

query = 
from(u in User, 
inner_join: m in Movie, 
on: u.movie_id == m.id, 
select: [m.title, u.name])
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estamos buscando os filmes e o nome do usuário que cada um recebeu. Para isso, começamos a nossa query na tabela User, depois fazemos um inner_join na tabela de filmes e cujo a condição do ID do filme do usuário é igual ao ID do filme. Por fim, a gente faz a seleção dos campos que queremos mostrar.

Image description

Usando LEFT JOIN

query = 
from(m in Movie, 
left_join: u in User, 
on: u.movie_id == m.id, 
where: u.name == "Floki O Gato" and m.title == "Um Sonho de Liberdade", 
select: [m.title, u.name])
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, buscamos filmes que contém o usuário "Floki O Gato". Para isso, começamos a query na tabela Movie, depois fazemos um left_join na tabela User e cujo a condição do ID do filme do usuário é igual ao ID do filme eu busco por usuário "Floki O Gato" onde o titulo do filme é "Um Sonho de Liberdade". Por fim, a gente faz a seleção dos campos que queremos mostrar.

Image description

Usando LEFT EXCLUDING JOIN

Filmes que não tiveram nenhum usuário

Image description

Usando RIGHT JOIN

query = 
from(m in Movie, 
right_join: u in User, 
on: u.movie_id == m.id, 
select: [m.title, u.name])
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estou buscando os filmes com o usuário que foi recebido.

Image description

Usando RIGHT EXCLUDING JOIN

Buscar os filmes com os usuário que cada um recebeu

query = 
from(m in Movie, 
right_join: u in User, 
on: u.movie_id == m.id, 
where: not is_nil(u.name), 
select: [m.title, u.name])
Enter fullscreen mode Exit fullscreen mode

Image description

Fragment

Forma de chamar funções em SQL puro no Ecto

query = 
from(m in Movie, 
select: fragment("upper(?)", m.title))
Enter fullscreen mode Exit fullscreen mode

Estamos fazendo uma listagem de títulos de filme em uppercase fragment(upper) que é uma função do Postgres.

Image description

OU

title = "O Poderoso Chefão"
query = from(m in Movie, 
where: m.title == ^title, 
select: fragment("upper(?)", m.title))
Enter fullscreen mode Exit fullscreen mode

Quando queremos colocar um valor de uma variável dentro da querie a gente precisa colocar operador pinar (^) se não, dará erro de compilação.

Image description

LIKE

Forma de busca por campo de texto

title = "O"
query = 
from(m in Movie, 
where: like(m.title, ^"#{title}%"), 
select: fragment("upper(?)", m.title))
Enter fullscreen mode Exit fullscreen mode

Filtrando títulos de filme que começam com a letra O.

Então, nesse nosso exemplo quero buscar os filmes que começam com O, então eu uso a função do Ecto LIKE passando o campo de texto que eu quero interpolar e o sinal de pinar, por fim o porcent % que é para dar match em qualquer termo.

Image description

E é isso! =)

Conclusão

Muito obrigado pela leitura até aqui e espero ter ajudado de alguma forma. Tem alguma sugestão ou encontrou algum problema? por favor deixe-me saber. 💜

Top comments (2)

Collapse
 
tiagodanin profile image
Tiago Danin

Incrível 👏

Collapse
 
rohlacanna profile image
Rômulo Silva

Uma honra receber seu feedback!
Tmj Tiago 💜

Timeless DEV post...

How to write a kickass README

Arguably the single most important piece of documentation for any open source project is the README. A good README not only informs people what the project does and who it is for but also how they use and contribute to it.

If you write a README without sufficient explanation of what your project does or how people can use it then it pretty much defeats the purpose of being open source as other developers are less likely to engage with or contribute towards it.