如何使用 Ecto 加入多个存储库?

Posted

技术标签:

【中文标题】如何使用 Ecto 加入多个存储库?【英文标题】:How to join multiple repositories with Ecto? 【发布时间】:2020-02-19 01:57:30 【问题描述】:

我有两个数据库,主数据库(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,并且有很多即时构建的查询。这就是为什么我不能像上面发布的那样只执行纯 SQL 查询,并且应该有基于 Ecto 的解决方案。有没有办法与 Ecto 进行这种加入?

【问题讨论】:

【参考方案1】:

它不漂亮,但你可以利用 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 中对我有用。

【讨论】:

以上是关于如何使用 Ecto 加入多个存储库?的主要内容,如果未能解决你的问题,请参考以下文章

在 Postgres 9.4+ 中索引 JSONB 嵌入式 Ecto2 模型

存储库模式:如何延迟加载?或者,我应该拆分这个聚合吗?

使用动态运算符创建 Ecto 查询

如何在 Elixir Ecto 中使用“between”创建 SQL

Elixir ecto 2 创建 many_to_many 关联

如何使用 FIND 递归备份多个颠覆存储库