MongoDB : use $ positional operator for querying
Asked Answered
D

4

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 !

Derekderelict answered 8/6, 2011 at 14:21 Comment(1)
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.Wengert
D
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

Detta answered 8/6, 2011 at 15:16 Comment(3)
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 !Derekderelict
Agreed... please vote for the issue in Jira to help get it into the product.Detta
Apparently was not implemented :(, they suggest using $elemMatch .Turne
M
8

What you are looking for is the $elemMatch operator.

Matrilineage answered 24/6, 2012 at 13:14 Comment(1)
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 ?Whipperin
D
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!

Deathblow answered 23/8, 2011 at 15:59 Comment(0)
T
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)
                            )
                        ));
Theresita answered 24/7, 2013 at 16:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.