I don’t think WHERE IN itself is actually supported in Ecto, because it’s basically always re-written as a join anyway. https://hexdocs.pm/ecto/Ecto.Query.html#subquery/2 is how you do queries inside of queries, and it explicitly only supports that in from and join.
From a quick perusal of the Ecto docs it looks like it is not currently possible:
If you attempt to write it as where: p.id in ^subquery(foo), Ecto won’t accept such query. However, the subquery above can be written as a JOIN, which is supported by Ecto. The final Ecto query will look like this:
No. Not directly. subqueries are supported using JOIN syntax. Something like:
tags_subquery = from(p in PostTags, where: p.tag == ^tag_value, select: p.post_id)
Repo.all(from(p in Posts, join: t in subquery(tags_subquery), on: p.id == t.post_id))
other than that I believe you are left with fragments. good luck.
Thanks for all your time, help and suggestions. I guess I will have to use joins instead then, even though I sometimes prefer writing in the subquery form.
Ectos fragment API is a no go since I have not found a good way (yet) of combining that approach with my usage of query prefixes.
I think both my wisdom and Ecto has improved in 5 years It can be done with both fragment and subquery as you pointed out.
def find_tagged_posts_with_fragment(tag) do
Ecto.Query.from(p in Post,
where: fragment("? = (select post_id from post_tags where post_tags.tag = ?)", p.id, ^tag)
)
|> Repo.all()
end
def find_tagged_posts_with_subquery(tag) do
tagged_posts = Ecto.Query.from(t in PostTag, select: t.post_id, where: t.tag == ^tag)
Ecto.Query.from(p in Post,
where: p.id in subquery(tagged_posts)
)
|> Repo.all()
end