Ecto:来自两个表的 select 个字段
Ecto: select fields from two tables
我有以下功能:
def get(fields_from_book, fields_from_author) do
Books
|> join(:left, [b], a in Author, on: b.id == a.book_id)
|> select([b, a], fields_from_book, fields_from_author)
|> Repo.all()
我对 select([b, a], fields_from_book, fields_from_author)
行感兴趣。在 Ecto 中有什么方法可以分别指定两个表中的两个字段数组?
是的,这可以在自定义宏的帮助下实现。该方法或多或少与 Ecto.Query.dynamic/2
.
中的方法相同
def query(fields_from_book, fields_from_author) do
from b in Book,
join: a in Author,
on: on: b.id == a.book_id,
select: ??? # {b.title, a.name}
现在我们需要用宏构建 select 表达式。让我们看看我们期望得到什么。
iex> quote do: {a.name, b.title, b.price}
#⇒ {:{}, [],
# [
# {{:., [], [{:a, [], Elixir}, :name]}, [no_parens: true], []},
# {{:., [], [{:b, [], Elixir}, :title]}, [no_parens: true], []},
# {{:., [], [{:b, [], Elixir}, :price]}, [no_parens: true], []}
# ]}
好的,让我们来实现这个(下面我假设字段列表作为编译时文字传递,例如列表。)
defmacrop select_many(books, authors) do
all =
Enum.map(books,
&{{:., [], [{:b, [], Elixir}, &1]}, [no_parens: true], []}) ++
Enum.map(authors,
&{{:., [], [{:b, [], Elixir}, &1]}, [no_parens: true], []})
quote do: {unquote_splicing(all)}
end
并将其用作:
def query(fields_from_book, fields_from_author) do
from b in Book,
join: a in Author,
on: on: b.id == a.book_id,
select: select_many(fields_from_book, fields_from_author)
未经测试,但应该可以。
摘自ecto docs: Defining custom functions using macros and fragment。
最后看来,我想出了一个简单的解决办法:
fields_book = [:code, :title_code, :publication_date,]
fields_author = [:name]
Book
|> join(:left, [b], a in assoc(b, :author))
|> select([b, a], merge(map(b, ^fields_book), map(a, ^fields_author)))
|> Repo.all()
我有以下功能:
def get(fields_from_book, fields_from_author) do
Books
|> join(:left, [b], a in Author, on: b.id == a.book_id)
|> select([b, a], fields_from_book, fields_from_author)
|> Repo.all()
我对 select([b, a], fields_from_book, fields_from_author)
行感兴趣。在 Ecto 中有什么方法可以分别指定两个表中的两个字段数组?
是的,这可以在自定义宏的帮助下实现。该方法或多或少与 Ecto.Query.dynamic/2
.
def query(fields_from_book, fields_from_author) do
from b in Book,
join: a in Author,
on: on: b.id == a.book_id,
select: ??? # {b.title, a.name}
现在我们需要用宏构建 select 表达式。让我们看看我们期望得到什么。
iex> quote do: {a.name, b.title, b.price}
#⇒ {:{}, [],
# [
# {{:., [], [{:a, [], Elixir}, :name]}, [no_parens: true], []},
# {{:., [], [{:b, [], Elixir}, :title]}, [no_parens: true], []},
# {{:., [], [{:b, [], Elixir}, :price]}, [no_parens: true], []}
# ]}
好的,让我们来实现这个(下面我假设字段列表作为编译时文字传递,例如列表。)
defmacrop select_many(books, authors) do
all =
Enum.map(books,
&{{:., [], [{:b, [], Elixir}, &1]}, [no_parens: true], []}) ++
Enum.map(authors,
&{{:., [], [{:b, [], Elixir}, &1]}, [no_parens: true], []})
quote do: {unquote_splicing(all)}
end
并将其用作:
def query(fields_from_book, fields_from_author) do
from b in Book,
join: a in Author,
on: on: b.id == a.book_id,
select: select_many(fields_from_book, fields_from_author)
未经测试,但应该可以。
摘自ecto docs: Defining custom functions using macros and fragment。
最后看来,我想出了一个简单的解决办法:
fields_book = [:code, :title_code, :publication_date,]
fields_author = [:name]
Book
|> join(:left, [b], a in assoc(b, :author))
|> select([b, a], merge(map(b, ^fields_book), map(a, ^fields_author)))
|> Repo.all()