3

In my Rails app I am using MongoID with a Elasticsearch river for text search.

For @devices_with_config = ConfigTextSearch.search params[:device_id] I want to extract just the device_id fields for the matching records in the query. In mongoID 3.1.0 I could just use Band.all.pluck(:name). But unfortunately, I am stuck with 3.0.23.

I see there is a similar moped expression collections[:bands].find.select(name: 1)...but I am new to rails and can't figure out how I would use a moped expression in a controller or model.

Any Ideas on how I can just extract the 'device_id' field in matches with MongoId?

dman
  • 10,406
  • 18
  • 102
  • 201

6 Answers6

3

Mongoid has a pluck function now.

mongoid#pluck

Mike S
  • 11,329
  • 6
  • 41
  • 76
1

You can get a hold of a Moped collection like this

 Band.collection.find.select(name: 1)
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
1

It seems like you're not actually building a Mongoid criteria with that call, but I haven't looked into elasticsearch-rails so I can't be 100% sure.

If you're completely unable to update to 3.1.0 you should be able to just monkey patch this functionality in.

module Mongoid
  class Criteria
    # select specific fields from collection based on current scope, returned as a hash
    def pluck(*fields)
      raise ArgumentError, 'Call this with at least one field' if fields.empty?

      collection.find(self.selector).select(Hash[fields.map { |field| [field, 1] }]).to_a
    end
  end
end

After adding the above code you should be able to do the following:

Band.where(name: 'awesome').pluck(:id, :device_id)
Jay
  • 4,240
  • 3
  • 26
  • 39
1

An equivalent to the pluck method defined in mongoid is:

plucked_array = User.where(:name => 'xyz').map(&: field_to_be_plucked)

Where field_to_be_plucked is the name of the field whose values need to be plucked out in Array.

Pushp Raj Saurabh
  • 1,174
  • 12
  • 16
  • 2
    This is loading the whole document (and embedded documents) from mongodb which is pretty inefficient, a better implementation if you're forced to use `map` would be: `User.where(name: 'xyz').only(:email).map(&:email)` which will only load the one field you're looking at :) – Jay Aug 10 '15 at 01:38
0

Found it....from what I can tell this isn't on the MongoId docs.....

sue = bob.results.map { |r| r._source.device_id }

dman
  • 10,406
  • 18
  • 102
  • 201
0

What I used for the same purpose, with Mongoid 3.0 :

Band.all.distinct(:name)

Warning: relevant only if all the names are different (of if you want to remove duplicates).

Brilnius
  • 29
  • 5
  • This really does not answer the question. – Daniel Wisehart Sep 14 '16 at 15:15
  • I disagree. This solution works (with the limitation I gave as a warning).In my opinion, it seems preferable compared to solution where the rows are iterated in memory (e.g. using map()). – Brilnius Dec 02 '16 at 12:59