我有一个Post
模式,其中包含一个虚拟字段children
,当前正在通过首先获取我的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
索引页面并且必须为列出的每个帖子都运行附加的子查询时,它的效率非常低。
答案 0 :(得分:1)
我认为子查询无法以这种方式进行参数化,因为它要在主查询之前 执行。可以将两个条件都移到主查询中。
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
粘贴到它的每个子级上时产生了一些多余的结果,但是我没有设法使其更好。
现在您只需要拆分结果。
{post, children} =
case Repo.all(children) do
[[_, post] | _] = result -> {post, Enum.map(result, &hd/1)}
[] -> {Repo.get(Post, p_id), []}
end
需要后一个查询,因为当没有子级时,联接将返回一个空集。