如何使用 Ecto 加入多个存储库?
How to join multiple repositories with Ecto?
我有两个数据库,主数据库(PostgreSQL)+统计数据库(ClickHouse)。统计数据库包含来自主数据库的一部分数据,足以执行计算。两个数据库中的所有 ID 都相似 (:binary_id
)。我需要找到一种方法,将从统计数据库获得的结果与对主数据库的查询结合起来。就纯 SQL 解决方案而言,它可能是这样的,其中 VALUES
是从统计数据库中获取的数据:
SELECT p0."id",
p0."name",
f1."average_count"
FROM "persons" AS p0
JOIN (VALUES (0.0, '906af2c0-cde2-4996-9a98-bdbf986fe687'::uuid),
(0.2857142857142857, 'aba7c694-3453-4a55-aab9-4b542dbb4ba9'::uuid),
(0.2857142857142857, '2dab3350-6149-4752-a55e-7477a6ad0dd3'::uuid))
as f1 (average_count, user_id)
on f1.user_id = p0.id;
我的项目积极使用 Ecto 并且有很多即时构建的查询。这就是为什么我不能像上面 post 那样只执行纯 SQL 查询并且应该有基于 Ecto 的解决方案。有没有办法用 Ecto 做这样的连接?
它不是很漂亮,但您可以利用 Postgres 的优势 UNNEST
:
users = [
%{id: "906af2c0-cde2-4996-9a98-bdbf986fe687", average_count: 0.0},
%{id: "aba7c694-3453-4a55-aab9-4b542dbb4ba9", average_count: 0.2857142857142857},
%{id: "2dab3350-6149-4752-a55e-7477a6ad0dd3", average_count: 0.2857142857142857}
]
{ids, average_counts} =
users
|> Stream.map(&{&1.id, &1.average_count})
|> Enum.unzip()
dumped_ids =
for id <- ids do
{:ok, dumped} = Ecto.UUID.dump(id)
dumped
end
query =
from p in Person,
join: f in fragment("SELECT UNNEST(?::uuid[]) AS user_id, UNNEST(?::float[]) AS average_count", ^dumped_ids, ^average_counts),
on: f.user_id == p.id,
select: %{id: p.id, name: p.name, average_count: f.average_count}
Repo.all(query)
也许这不是最好的方法。我不是数据库专家。但这在 IEx 中对我有用。
我有两个数据库,主数据库(PostgreSQL)+统计数据库(ClickHouse)。统计数据库包含来自主数据库的一部分数据,足以执行计算。两个数据库中的所有 ID 都相似 (:binary_id
)。我需要找到一种方法,将从统计数据库获得的结果与对主数据库的查询结合起来。就纯 SQL 解决方案而言,它可能是这样的,其中 VALUES
是从统计数据库中获取的数据:
SELECT p0."id",
p0."name",
f1."average_count"
FROM "persons" AS p0
JOIN (VALUES (0.0, '906af2c0-cde2-4996-9a98-bdbf986fe687'::uuid),
(0.2857142857142857, 'aba7c694-3453-4a55-aab9-4b542dbb4ba9'::uuid),
(0.2857142857142857, '2dab3350-6149-4752-a55e-7477a6ad0dd3'::uuid))
as f1 (average_count, user_id)
on f1.user_id = p0.id;
我的项目积极使用 Ecto 并且有很多即时构建的查询。这就是为什么我不能像上面 post 那样只执行纯 SQL 查询并且应该有基于 Ecto 的解决方案。有没有办法用 Ecto 做这样的连接?
它不是很漂亮,但您可以利用 Postgres 的优势 UNNEST
:
users = [
%{id: "906af2c0-cde2-4996-9a98-bdbf986fe687", average_count: 0.0},
%{id: "aba7c694-3453-4a55-aab9-4b542dbb4ba9", average_count: 0.2857142857142857},
%{id: "2dab3350-6149-4752-a55e-7477a6ad0dd3", average_count: 0.2857142857142857}
]
{ids, average_counts} =
users
|> Stream.map(&{&1.id, &1.average_count})
|> Enum.unzip()
dumped_ids =
for id <- ids do
{:ok, dumped} = Ecto.UUID.dump(id)
dumped
end
query =
from p in Person,
join: f in fragment("SELECT UNNEST(?::uuid[]) AS user_id, UNNEST(?::float[]) AS average_count", ^dumped_ids, ^average_counts),
on: f.user_id == p.id,
select: %{id: p.id, name: p.name, average_count: f.average_count}
Repo.all(query)
也许这不是最好的方法。我不是数据库专家。但这在 IEx 中对我有用。