查询 a 的另一端的某物 has many 通过关联
Query something on the other end of a has many through association
我想通过一个has many through关联查询的结果进行过滤。我必须使用 Elixir 来完成这项工作,还是可以使用 Ecto 在数据库中完成这项工作?
设置
mix phx.new shop
cd shop
mix echo.create
mix phx.gen.html Accounting Invoice invoices number issues_on:date
mix phx.gen.html Accounting Product products name category
mix phx.gen.html Accounting LineItem line_items
invoice_id:references:invoices
product_id:references:products
mix ecto.migrate
priv/repo/seeds.exs
{:ok, invoice1} = Shop.Accounting.create_invoice(%{number: "1", issued_on: "2017-01-01"})
{:ok, invoice2} = Shop.Accounting.create_invoice(%{number: "2", issued_on: "2017-01-01"})
{:ok, invoice3} = Shop.Accounting.create_invoice(%{number: "3", issued_on: "2017-01-02"})
{:ok, banana} = Shop.Accounting.create_product(%{name: "Banana", category: "Fruits"})
{:ok, potato} = Shop.Accounting.create_product(%{name: "Potato", category: "Vegetables"})
Shop.Accounting.create_line_item(%{invoice_id: invoice1.id, product_id: banana.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice2.id, product_id: banana.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice2.id, product_id: potato.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice3.id, product_id: potato.id})
架构
lib/shop/accounting/invoice.ex
schema "invoices" do
field :issued_on, :date
field :number, :string
has_many :line_items, Shop.Accounting.LineItem
has_many :products, through: [:line_items, :product]
timestamps()
end
lib/shop/accounting/line_item.ex
schema "line_items" do
belongs_to :invoice, Shop.Accounting.Invoice
belongs_to :product, Shop.Accounting.Product
timestamps()
end
查询预装蔬菜的发票
我如何查询从 1 月 1 日到 1 月 5 日的所有 invoices
,包括 products
的值 Vegetables
for a category
。
如果他们也有 line_items
水果也没关系。我只是想确保没有 invoice
只有水果没有蔬菜。有了这个种子,它将成为发票 2 和 3。
我知道如何使用 Elixir 过滤 invoices
。但我想知道我是否可以用 Ecto 更快地在数据库中解决这个问题。有没有办法用 Ecto 过滤它?
import Ecto.Query
alias Shop.Accounting.Invoice
alias Shop.Repo
{:ok, starts_on} = Date.from_erl({2017, 1, 1})
{:ok, ends_on} = Date.from_erl({2017, 1, 5})
query = from i in Invoice, where: i.issued_on >= ^starts_on,
where: i.issued_on <= ^ends_on,
preload: [:products]
invoices = Repo.all(query)
# Here I would loop through invoices to filter the once
# with vegetables.
使用 Ecto.Query
join
: https://hexdocs.pm/ecto/Ecto.Query.html#join/5
在您的情况下,它将是:
query = from i in Invoice, where: i.issued_on >= ^starts_on,
where: i.issued_on <= ^ends_on,
join: p in assoc(i, :products),
where: p ...,
preload: [:products]
并在您想要的条件下工作。
另外,我在学习Ecto的时候经常用到这些例子:https://elixirnation.io/references/ecto-query-examples
它们有点过时,但总体上还不错。
我想通过一个has many through关联查询的结果进行过滤。我必须使用 Elixir 来完成这项工作,还是可以使用 Ecto 在数据库中完成这项工作?
设置
mix phx.new shop
cd shop
mix echo.create
mix phx.gen.html Accounting Invoice invoices number issues_on:date
mix phx.gen.html Accounting Product products name category
mix phx.gen.html Accounting LineItem line_items
invoice_id:references:invoices
product_id:references:products
mix ecto.migrate
priv/repo/seeds.exs
{:ok, invoice1} = Shop.Accounting.create_invoice(%{number: "1", issued_on: "2017-01-01"})
{:ok, invoice2} = Shop.Accounting.create_invoice(%{number: "2", issued_on: "2017-01-01"})
{:ok, invoice3} = Shop.Accounting.create_invoice(%{number: "3", issued_on: "2017-01-02"})
{:ok, banana} = Shop.Accounting.create_product(%{name: "Banana", category: "Fruits"})
{:ok, potato} = Shop.Accounting.create_product(%{name: "Potato", category: "Vegetables"})
Shop.Accounting.create_line_item(%{invoice_id: invoice1.id, product_id: banana.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice2.id, product_id: banana.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice2.id, product_id: potato.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice3.id, product_id: potato.id})
架构
lib/shop/accounting/invoice.ex
schema "invoices" do
field :issued_on, :date
field :number, :string
has_many :line_items, Shop.Accounting.LineItem
has_many :products, through: [:line_items, :product]
timestamps()
end
lib/shop/accounting/line_item.ex
schema "line_items" do
belongs_to :invoice, Shop.Accounting.Invoice
belongs_to :product, Shop.Accounting.Product
timestamps()
end
查询预装蔬菜的发票
我如何查询从 1 月 1 日到 1 月 5 日的所有 invoices
,包括 products
的值 Vegetables
for a category
。
如果他们也有 line_items
水果也没关系。我只是想确保没有 invoice
只有水果没有蔬菜。有了这个种子,它将成为发票 2 和 3。
我知道如何使用 Elixir 过滤 invoices
。但我想知道我是否可以用 Ecto 更快地在数据库中解决这个问题。有没有办法用 Ecto 过滤它?
import Ecto.Query
alias Shop.Accounting.Invoice
alias Shop.Repo
{:ok, starts_on} = Date.from_erl({2017, 1, 1})
{:ok, ends_on} = Date.from_erl({2017, 1, 5})
query = from i in Invoice, where: i.issued_on >= ^starts_on,
where: i.issued_on <= ^ends_on,
preload: [:products]
invoices = Repo.all(query)
# Here I would loop through invoices to filter the once
# with vegetables.
使用 Ecto.Query
join
: https://hexdocs.pm/ecto/Ecto.Query.html#join/5
在您的情况下,它将是:
query = from i in Invoice, where: i.issued_on >= ^starts_on,
where: i.issued_on <= ^ends_on,
join: p in assoc(i, :products),
where: p ...,
preload: [:products]
并在您想要的条件下工作。
另外,我在学习Ecto的时候经常用到这些例子:https://elixirnation.io/references/ecto-query-examples
它们有点过时,但总体上还不错。