Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to match mongoid documents using array fields in query?

I am trying to match documents with Mongoid/Mongodb where array fields are used in the query. I've been struggling with $elemMatch but can't seem to get it.

Context

  • A Project can have admin, member, reader users
  • These users are referenced by a Project (HABTM)
  • I want to be able to find projects where:
    • User A is admin
    • User B is admin or member
    • .. etc ..

Example

Given a Project document from Rails console:

[#<Project _id: 4f44355a9f5b7f385a000003, 
  _type: nil, name: "Project ABC", 
  desc: "some description", 
  admin_ids: 
    [BSON::ObjectId('123')], 
  member_ids: 
    [BSON::ObjectId('456'),
    BSON::ObjectId('789')], 
  reader_ids: []
>]

I had the following code:

@projects = Project.any_of({:admin_ids => [current_user.id]}, 
                           {:member_ids => [current_user.id]}).entries

Which matches current_user.id across either admin_ids and member_ids as long as there was only a single value in either of the arrays. As per the code above:

  • Trying to match user '123' gives correct result
  • Trying to match user '456' gives no result (incorrect)

$elemMatch

Based on researching, I think I should be using $elemMatch but am missing something.

As per the Project document code above:

// test case: this works with array of one
Project.all(conditions: {:admin_ids => "123"}).entries

// failure case: empty result   
Project.all(conditions: {:member_ids => {'$elemMatch' => {:id => '456' } }}).entries

// failure case: empty result
Project.all(conditions: {:member_ids => {'$elemMatch' => {:id => BSON::ObjectId('4f44a4019f5b7f3d5200000d') } }}).entries
like image 468
Daniel May Avatar asked Feb 22 '12 09:02

Daniel May


People also ask

How do you match an array element in MongoDB?

The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria. If you specify only a single <query> condition in the $elemMatch expression, and are not using the $not or $ne operators inside of $elemMatch , $elemMatch can be omitted.

How do I query an array object in MongoDB?

To search the array of object in MongoDB, you can use $elemMatch operator. This operator allows us to search for more than one component from an array object.

How do you check if a value exists in an array in MongoDB?

You can just simply use count method.

How do I pull an array in MongoDB?

The $pull operator removes from an existing array all instances of a value or values that match a specified condition. The $pull operator has the form: { $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } } To specify a <field> in an embedded document or in an array, use dot notation.


2 Answers

You need to get rid of the array while querying.

@projects = Project.any_of({:admin_ids => current_user.id}, 
                       {:member_ids => current_user.id}).entries

That should work.

like image 83
rubish Avatar answered Oct 27 '22 01:10

rubish


I think you should just be able to use $in rather than $elemMatch - as the mongodocs say:

"You only need to use [$elemMatch] when more than one field must be matched in the array element."

Have you tried something like the following?

Project.any_in(:member_ids =>  [ member_id_one, member_id_two ])
like image 37
Russell Avatar answered Oct 27 '22 00:10

Russell