holandes22
I have an Entry with a many-to-many relationship to Tag. Like so:
defmodule Tag do
...
schema "tags" do
field :name, :string
end
end
defmodule Entry do
...
schema "links" do
...
many_to_many :tags, Tag, join_through: "entries_tags",
end
end
Join table :entries_tags, has
:entry_id, references(:entries)
:tag_id, references(:tags)
Now, I want to filter based on a list of tags. I’m using this query
from entry in Entry,
preload: [:tags],
distinct: entry.id,
join: tag in assoc(entry, :tags),
where: tag.name in ^tags #tags is a list of strings passed as a param
The the query above gives me all the entries that have at least
one tag in the filter list. So for example, if I have 3 entries like so:
- Entry.tags = [“a”, “b”, “c”]
- Entry.tags = [“a”, “d”]
- Entry.tags = [“d”]
and I filter with tags [“a”, “b”], it will match both #1 and #2.
My problem is that I want only to get the entries that have the filter tags as a subset of
their associated tags, meaning that using the same values as in the example above, the
returned list should only contain the entry #1
Any idea how can I construct such a query?
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
yurko
I’d start with Tag and not the entry, select needed tags with OR and then join their entries
holandes22
Thanks, I tried your approach I started by getting the tags that include the filters:
but now I get stuck on how to join with the entries.
Using once more the example from my post, the query above with filters [“a”, “b”] gives me 2 Tags:
I cannot just join and get all the related entries to those 2 tags since it would return entries #1 and #2. It should instead only return entry #1 as is the one that belongs to all the filter tags.
Not sure how to check if the entries related to those tags contain all the filter_tags
yurko
ok it is indeed somewhat trickier then I thought at first. Here is how it might work, you might have to tweak this logic - I don’t have anything with ecto and many to many, so no code:
entries_tagsentries_tagsfor the given tag idthis way you’d only get entries that have all the tags. This thing might also have a simpler solution that I can’t think of at the moment
holandes22
Thanks for the help! sorry about the delayed answer, did not get to work on this yesterday (side learning project).
I wasn’t able to make it work, I’m clearly missing something out. I tried doing the following
but this effectively selects all the entries that have one of those tags. I’m missing a where clause that checks if all the tags are a subset of entry.tags, but I found nothing that would help with this in the Ecto.Query docs. Any idea how would I be able to filter like that?
yurko
you’d have to (at least at first) use separate
whereclauses, they work withandby default. Something like thisholandes22
Quite probably I misunderstood, but I don’t think that would work, since entries_tags has a reference to a unique tag. So there won’t be any entries_tags that has a reference to both tag1 and tag2 at the same time.
OvermindDL1
I’d probably just do this (I don’t use invisible many-to-many joins, I like explicit tables, so I’ll imagine your
entries_tagsjoin table exposed asEntriesTags, I’ll also imagine you have a unique index field as a composite of the entry and tag foreign keys as I always do for many-to-many joins of this form, I would also add a virtual_rankfield onEntry, I add that field to almost all my models just for purposes like this since Ecto has no good way to convert a struct return table to a map while adding a column (*hint*hint*, we need that)):Another alternative is to just aggregate all the tags into an array via
array_agg, however that would require adding yet another virtual field on your schema or to manually specify everything you want returned in a map, assuming you do the latter:Or something like that…
yurko
entries_tagsis a join table, right? You haveentrieswith id,tagswith id andentries_tagsthat handles many to many relation? In this case yourentries_tagswill have unique pairs of ids, egto fetch entries that have both tags 1 and 2 you’d be able to use multiple where clauses
also what @OvermindDL1 said, if you have
EntriesTagsmodel for your join table you can use it directlyholandes22
Thank you @OvermindDL1 ! your second suggestion is what ultimately made it work.
I was trying to avoid to use raw sql as I was sure that there would be a way to accomplish this with Ecto’s DSL, but I guess the option it is there to deal with things that the DSL cannot cover.
My final query looks like so
I had to add the join in the final query to be able to return the entry based on the schema.
Selecting the fields manually as you suggested also worked but it seems tedious and would fail to add any eventual new field, although it probably is faster
I tried to avoid the join by using your suggestion of a virtual field in Entry, and making the query like so:
but that raised an error (originated from the second query)
** (Ecto.SubQueryError) the following exception happened when compiling a subquery.
Not sure what that error means, I’m guessing due to the related tags field.
OvermindDL1
Hmm, fantastic question. Can @michalmuskala or so assist? I’ve been hitting a lot of things that Ecto gives that a similar (though not exact) error at this location and I am really curious as to at least the reason for this one…