31

how do you retrieve an array of IDs in Mongoid?

arr=["id1","id2"]
User.where(:id=>arr)

You can do this easily if you are retrieving another attribute

User.where(:nickname.in=>["kk","ll"])

But I am wondering how to do this in mongoid -> this should be a very simple and common operation

zishe
  • 10,665
  • 12
  • 64
  • 103
meow
  • 27,476
  • 33
  • 116
  • 177

4 Answers4

50

Remember that the ID is stored as :_id and not :id . There is an id helper method, but when you do queries, you should use :_id:

User.where(:_id.in => arr)

Often I find it useful to get a list of ids to do complex queries, so I do something like:

user_ids = User.only(:_id).where(:foo => :bar).distinct(:_id)
Post.where(:user_id.in => user_ids)
Alupotha
  • 9,710
  • 4
  • 47
  • 48
bowsersenior
  • 12,524
  • 2
  • 46
  • 52
  • The solution above works fine when amount of users is small. But it will require a lot of memory while there are thousands of users. – dpaluy Oct 15 '12 at 20:30
  • @dpaluy you are right--this approach is only a hack. Also, the data can change between the first and second queries, especially when there are a lot of documents. Use with caution, or better yet, figure out a better way! – bowsersenior Oct 16 '12 at 19:28
  • 4
    The better way is to use `.distinct(:_id)` instead of `.map(&:_id)`. `distinct` works during executing the query which is slightly faster than telling rails to loop the array – Zakwan May 23 '14 at 17:06
5

Or simply:

arr = ['id1', 'id2', 'id3']
User.find(arr)
gjb
  • 6,237
  • 7
  • 43
  • 71
  • 1
    Issue with above: If just one id is not found, it will return error and not the ids that were found. – dman Jan 16 '15 at 18:24
  • `Mongoid.raise_not_found_error = false` will avoid document not found error raised on above query – r3bo0t Sep 23 '16 at 09:28
4

The above method suggested by browsersenior doesn't seem to work anymore, at least for me. What I do is:

User.criteria.id(arr)
Bryan L.
  • 891
  • 1
  • 7
  • 6
  • 3
    Just a quick note. With Mongoid 2.0.0 and later, you will need to use `for_ids` instead of `id` like so: `User.criteria.for_ids(arr)` – bowsersenior Apr 12 '11 at 04:13
2
user_ids = User.only(:_id).where(:foo => :bar).map(&:_id)
Post.where(:user_id.in => user_ids)

The solution above works fine when amount of users is small. But it will require a lot of memory while there are thousands of users.

User.only(:_id).where(:foo => :bar).map(&:_id)

will create a list of User objects with nil in each field except id.

The solution (for mongoid 2.5):

User.collection.master.where(:foo => :bar).to_a.map {|o| o['_id']}
dpaluy
  • 3,537
  • 1
  • 28
  • 42