0

Although the context is likely irrelevant, I'm using the Chewy gem to filter Elasticsearch results using this code:

scope = scope.filter {
      (send('facet_properties').send(property_ids[0], :or) == val.map(&:to_i)) |
          (send('facet_properties').send(property_ids[1], :or) == val.map(&:to_i))
    }

I'm looking for a way to loop through each element in property_ids rather than calling property_ids[0], property_ids[1], etc., separated by an or individually. In actual use property_ids will not be a fixed length.

Mauricio Moraes
  • 7,255
  • 5
  • 39
  • 59
Matt Dunbar
  • 950
  • 3
  • 11
  • 21
  • can you first get the count of property_id's and then run a loop N times? – Anthony Oct 28 '14 at 13:20
  • Looping through wouldn't allow the `|` comparison, at least not with a syntax I'm familiar with. For a non chewy specific solution this seems to work: `scope = scope.filter { property_ids.map { |k| send('facet_properties').send(k, :or) == val.map(&:to_i) }.reduce do |memo, o| memo | o end }`, the accepted answer shows a better chewy specific solution. – Matt Dunbar Oct 28 '14 at 13:48
  • 1
    I'm not familiar with the context, but suspect this may work: `scope = scope.filter { property_ids.reduce(false) { |tf, id| (send('facet_properties').send(id, :or) == val.map(&:to_i)) | tf } }`. – Cary Swoveland Oct 28 '14 at 15:54
  • Thanks @Cary - This looks like a better approach for my initial question and what I'd use if the chewy gem wasn't capable of searching many keys to many values (which I was unaware of until the answer below). – Matt Dunbar Oct 29 '14 at 07:34

1 Answers1

2

Not sure exactly what your structure looks like or exactly what you are trying to achieve but have you tried something like this?

vals = val.map(&:to_i)
prop_hash = Hash[property_ids.map{|prop| [prop,vals]}]
# alternately prop_hash = property_ids.each_with_object({}){|prop,obj| obj[prop] = vals}
scope.filter(facet_properties: {prop_hash}).filter_mode(:or)

Since chewy has a #filter_mode method to set the join type for where conditions it seems like this should work for you.

engineersmnky
  • 25,495
  • 2
  • 36
  • 52
  • Interesting. I had just come up with another solution based on a chat in IRC using .reduce, this is chewy specific, but for anyone looking to answer this question more generically the .reduce approach works: `scope = scope.filter { property_ids.map { |k| send('facet_properties').send(k.to_s, :or) == val.map(&:to_i) }.reduce do |memo, o| memo | o end }` – Matt Dunbar Oct 28 '14 at 13:44