使用子查询或连接将同一模式上的两个 ecto 查询合并为一个

Combine two ecto queries on the same schema into one with subquery or join

我有一个带有虚拟字段 childrenPost 架构,我目前正在通过 运行 在第一次获取我的 Post 后进行第二个查询来填充它。

初始查询得到 Post:

post = Post |> Repo.get(id)

然后我 运行 进行第二个查询以获取其子项并更新虚拟 children 字段:

children_query =
    from(p in Post,
      where: fragment("hierarchy <@ ?", ^post.hierarchy),
      order_by: p.inserted_at
    )

children = Repo.all(children_query)
post = Map.merge(post, %{children: children})

层次结构字段在数据库中存储为 Ltree,在架构中具有 :string 类型。

有什么方法可以将这些查询合并为一个吗?我尝试使用 Ecto subquery/2 函数,但无法理解它。

我试过了,但无法弄清楚如何将 Post(在本例中为 p)传递到子查询中,而不会在连接行上出现 the variable p is undefined 的错误。

  def children_query(post) do
    from p in Post,
    where: fragment("hierarchy <@ ?", ^post.hierarchy),
    order_by: v.inserted_at
  end

  def get_post(p_id) do
    from(p in Post, 
    where: p.id == ^p_id,
    join: c in subquery(children_query(p)),
    on: p.id == c.id, # not sure how it would join on
    select: %{p | children: c}
    )
  end

我想解决这个问题,因为当显示 Post 索引页面并且必须 运行 对列出的每个 post 进行额外的子查询时,它变得非常低效。

我想子查询不能以这种方式参数化,因为它要在主查询之前执行。可以将这两个条件移动到主查询中。

children = 
  from(p in Post,
       join: s in subquery(from p in Post),
       where: p.id == ^p_id and fragment("? <@ ?", s.hierarchy, p.hierarchy),
       select: [s, p])

上面产生了一些多余的结果,Post 粘在每个 children 上,但我没有设法让它变得更好。

现在只需要拆分结果即可。

{post, children} =
  case Repo.all(children) do
    [[_, post] | _] = result -> {post, Enum.map(result, &hd/1)}
    [] -> {Repo.get(Post, p_id), []}
  end

需要后一个查询,因为当没有 children 时,连接 returns 一个空集。