【发布时间】:2018-06-01 03:22:21
【问题描述】:
我正在尝试使用左连接构建一个 Ecto 查询,该连接带有可选的额外条件。我将尝试用典型的帖子和 cmets 示例来描述它。
发表 has_many 评论 评论belongs_to Post。
假设评论有两个布尔字段,已批准和精选。
我想获取所有帖子,无论它们是否有 cmets,因此左连接。 我想要预加载 cmets,但最好是一个 SQL 查询。 我想选择性地过滤已批准和精选的 cmets。
我正在尝试编写一个类似这样的函数,如果批准或特色不为零,它们将被包含在连接中,如果它们为零,它们将被忽略。我还没有找到比这样更好的方法:
def posts_with_comments(approved, featured, some_var) do
query = Post
|> where([p], p.some_field == ^some_var
cond do
!is_nil(approved) and !is_nil(featured)
-> join(query, :left, [p], c in Comment, [post_id: p.id, approved: ^approved, featured: ^featured])
!is_nil(approved)
-> join(query, :left, [p], c in Comment, [post_id: p.id, approved: ^approved])
!is_nil(featured)
-> join(query, :left, [p], c in Comment, [post_id: p.id, featured: ^featured])
true -> join(query, :left, [p], c in Comment, [post_id: p.id])
end
|> preload([p, c], [comments: c])
|> select([p], p)
|> Repo.all
end
这可行,但必须有更好的方法。如果我有第三个参数,那就太疯狂了。我正在寻找一种方法来为join() 的on 参数动态构建该列表。由于需要固定,我的尝试失败了。
我不能将这些条件放在where 中,因为如果我执行where t.approved == true 之类的操作,我只会得到批准的 cmets 帖子。
【问题讨论】:
-
为什么不使用警卫?比如
def posts_with_comments(approved, featured, some_var) do和def posts_with_comments(approved, featured, some_var) when is_nil?(approved) do等等 -
@Felipe-Skinner 如果我对您的理解正确,那可能会奏效,但我试图避免在警卫或任何地方进行条件测试。