7

I have a collection with entries that look like :

{
    "userid": 1, 
    "contents": [ 
            { "tag": "whatever", "value": 100 }, 
            {"tag": "whatever2", "value": 110 } 
    ] 
}

I'd like to be able to query on that collection and returning only one part of the array : the one matching the query. I'm trying to use the $ positional operator to do so but it hasn't worked so far.

Here is more precisely what I'd like to do :

collection.find({'contents.tag':"whatever"},{'contents.$.value':1})

As a result I expect sth with only the value corresponding to the entry in the array that matched query, which is 100 in this case.

Do you know what's wrong ? I was thinking that maybe the $ operator can only be used for update and not for querying. Anyone in the know ?

Thanks !

Ankur Verma
  • 5,793
  • 12
  • 57
  • 93
Johanisma
  • 2,058
  • 3
  • 22
  • 25
  • Just for the purpose to return only your value field, a `collection.find({'contents.tag':'whatever'},{'contents.value':1})` would be enough and doesn't need a positional operator. Nevertheless (as Ryan already mentioned in his answer) it's necessary to pull the field out of the returned array (which will also include the doc's `_id`) on app-side. Drawback is the fact a `findOne` or `limit(1)` concerning your nested array won't work, which wouldn't be a prob if you don't expect more than 1 result. – proximus Jun 08 '11 at 16:03

4 Answers4

8

What you are looking for is the $elemMatch operator.

Aidamina
  • 1,894
  • 20
  • 14
  • 2
    Can you elaborate a bit more on how $elemMatch can be used in this case to return only part of the matched object in the array ? – gaurav5430 Aug 29 '17 at 19:27
8

Yes, you are correct - the positional operator is used for updating an object.

The solution for now would be to return the array an pull the field out in your application.

There is an open enhancement request for this feature (in queries):

https://jira.mongodb.org/browse/SERVER-828

For more information on the positional operator, see:

http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator

Ryan
  • 553
  • 4
  • 6
  • Yes thanks for the answer. I guess I'm gonna have to do it on the application side for now ! It's pretty weird because if they implemented for update it shouldn't be very different for find...Anyways, hope the feature will come soon ! – Johanisma Jun 09 '11 at 13:17
  • 1
    Agreed... please vote for the issue in Jira to help get it into the product. – Ryan Jun 10 '11 at 13:40
  • Apparently was not implemented :(, they suggest using `$elemMatch` . – MaicolBen Mar 27 '14 at 13:36
0

Create a query with $in instead and add your equal value to the array, this can solve your issue

$users_array = array(xxxxxxxx,yyyyyy);     
$user = Db::find('fb_users', array(
                            'facebook_id' => array(
                                '$in' => array($users_array)
                            )
                        ));
Liad Livnat
  • 7,435
  • 16
  • 60
  • 98
0

It might be an overkill, but I guess you can use map-reduce for this.

first, pre-filter with a query, emit all array elements in map, filter the ones that do not match either in emit or in reduce. If you don't set out everything will happen in RAM.

If you have to run those kinds of queries often, it might be worthwhile to duplicate the data.

Nevertheless, I hope the SERVER-828 will be implemented soon!

Laura
  • 1,039
  • 1
  • 7
  • 3