Mongoid Scope Check If Array Field Contains Value

Luis Crespo picture Luis Crespo · Oct 10, 2014 · Viewed 7.9k times · Source

The solution for this question might look pretty simple, but I've been waving around with no answer.

I'm using Mongoid in my Rails 4.1.4 app. I have a model which contains an Array field that will house String values.

I need a Mongoid's scope in the model to retrieve those instances where this Array field contains a specific String value, given as a parameter to the scope. Let's say we have this model:

class SomeModel
  include Mongoid::Document
  include Mongoid::Timestamps

  field :some_array, type: Array, default: Array.new

  scope :some_scope, ->(value){ elem_match(some_array: value) }

end

The above scope doesn't work because, obviously, in MongoDB $elemMatch needs to receive a Criteria as the value. But, how would be the Criteria to just say that the element has to be equal to the given value???.

Any clues on how to write this pretty simple scope???.

Regards!!!. Thanks in advance.

Answer

mu is too short picture mu is too short · Oct 14, 2014

You're drastically overcomplicated things. If a field holds an array then you can search it as though it wasn't an array. For example, if you have this in a document:

{ some_array: [ 'where', 'is', 'pancakes', 'house?' ] }

and you do a query like this:

where(:some_array => 'pancakes')

you'll find that document. You don't need $elemMatch or anything complicated here; you can pretend that the array is a single value for simple queries like you have:

scope :some_scope, ->(value) { where(:some_array => value) }

You only need to get into $elemMatch if you want to apply multiple conditions to each element of the array, things like this from the $elemMatch docs:

   results: { $elemMatch: { $gte: 80, $lt: 85 } }
// ^^^^^^^array           ^^^^^^^^^^^^^^^^^^^^^multiple conditions

Don't feel bad, the current MongoDB docs aren't exactly clear on this stuff (or at least I can't find an explicit explanation).