igor

igor

How to add a group of or_where conditions to the query which already has some where closes

If I have a form with filters filtering entities by some field and I want to add a group of or_where closes to the query dynamically.
And the query could already have some where closes which I want my group of or_where to be separated from by AND operator in db query.
So, I’d like to build the function like:

def add_composite_where_to_query(query, field_name, values) do
  # here is something I can't figure out..
end

This function should add where closes to query like:
SELECT * from entities e where (e.field1=‘value1’ OR e.field1=‘value2’) AND (e.field2=‘value3’ OR e.field2=‘value4’ OR …)

I’ve already tried many ways, but no luck.
As examples of what didn’t work:

def add_composite_where_to_query(query, field_name, values) do
  Enum.reduce(values, query, fn(value, acc) ->
    or_where(acc, [q], field(q, ^field_name) == ^value)
  end)
end
def add_composite_where_to_query(query, field_name, values) do
    dynamic = Enum.reduce(values, query, fn(value, dynamic) ->
      or_where(dynamic, association, ^field_name == ^value)
    end)
    where(query, ^dynamic)
end
def add_composite_where_to_query(query, field_name, values) do
    dynamics = Enum.reduce(values, [], fn(value, dynamics) ->
      dynamic([q], field(q, ^field_name) == ^value)
    end)
    where(query, ^dynamics)
end

Most Liked

al2o3cr

al2o3cr

FWIW, or_where does things that aren’t exactly intuitive - see the failing test here for an example. Be careful when composing queries with it.

OTOH, based on the function heads above I wonder if you’d be better served by an IN query rather than ORs since the query is checking for a single field being one of multiple values.

LostKobrakai

LostKobrakai

So where as well as or_where don’t just add a new condition to a query, but they also do it in a certain precedence order: (all_prev_conditions_of_the_query) AND|OR (newly_added_condition_s). So order plays an important role when composing where conditions.

If you’re looking for a different composition of conditions then you should probably look into the dynamic macro to build up the conditions and only attach the final result to the actual query.

LostKobrakai

LostKobrakai

If you need to group (put parenthesis around) conditions in a particular fashion, which contradicts the way precedence is handled by the where and or_where handling, then you need to create logic to explicitly create dynamic‘s for each group separately and only in the end put those groups together. Simply reducing over everything once probably won‘t cut it for those more complex conditions. As you cannot „add parenthesis“ after the fact you need to build up the correct groups when you‘re composing the single parts.

igor

igor

Thanks for all of you, guys, especially for you, @LostKobrakai, it seems finally struck me, here is what I came to for now:

def build_query_from_filters(query, filters) do
  if length(filters) do
    first = hd(filters)
    tail = tail(filters)
    conditions = build_dynamic_from_filter(first)
    conditions = Enum.reduce(tail, conditions, fn(filter, conditions) ->
      filter_conditions = build_dynamic_from_filter(filter)
      dynamic([q], ^filter_conditions and ^conditions)
    end)
    query |> where(^conditions)
  else
    query
  end  
end

def build_dynamic_from_filter(filter) do
  if is_list(filter.value) do
    conditions = false
    Enum.reduce(filter.value, conditions, fn(value, conditions) ->
      dynamic([q], field(q, ^filter.field_name) ilike ^value or ^conditions)
    end)
  else
    dynamic([q], field(q, ^filter.field_name) ilike ^filter.value)
  end
end

Where Next?

Popular in Questions Top

aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement