stuporglue
stuporglue

Reputation: 591

Mongodb dot notation wildcard?

I have a collection of users, each of which may be subscribed to one or more services. Each service has some meta data, including the number of credits the user has for that service.

How can I find all of the user objects who have less than 50 credits for some service if I have no way of knowing what the service objects keys will be?

Conceptually, it would be something like this, which doesn't work:

db.users.find({services.*.credits : {$lt : 50}})

The users collection:

   {
_id: 4f0ea25072139e4d2000001f,
services : {
    a : { credits : 100, score : 2000 },
    b : { credits : 200, score : 300 },
    c : { credits : 10, score : 1300 }
    }
},
{
_id: 4f0ea25072139e4d2000001f,
services : {
    f : { credits : 68, score : 14 },
    q : { credits : 1000, score : 102 },
    z : { credits : 59, score : 352 }
    }
}

Another example of what I want to do, in case it's not clear here, is explained here: http://www.mongodb.org/display/DOCS/Advanced+Queries#comment-346075854

Upvotes: 29

Views: 13871

Answers (3)

CommaToast
CommaToast

Reputation: 12178

This is an actual answer to your question.

How you can find all of the user objects who have less than 50 credits for some service if you have no way of knowing what the service objects keys will be is as follows.

Use a $where query:

db.users.find({
    $where: function () {
        for (var index in this.services)
            if (this.services[index].credits < 50)
                return this;
    }
});

Upvotes: 29

mnemosyn
mnemosyn

Reputation: 46291

I don't know of a way to accomplish this using the schema you're using. It seems to me you're abusing objects as arrays. If services were an array (the plural hints that it should be), you could simply query

db.users.find({"services.credits" : { $lt : 50 }}); 

or use $elemMatch if you need to match multiple conditions on a single array element.

Upvotes: 1

Eve Freeman
Eve Freeman

Reputation: 33145

I think it would be easier if you put that services object into an array, so you can use $elemMatch, like:

{
  services : [
    {key: "a" , credits : 100, score : 2000 },
    {key: "b", credits : 200, score : 300 },
    {key: "c", credits : 10, score : 1300 }
  ]
}

and

{
  _id: 4f0ea25072139e4d2000001f,
  services : [
    {key: "f", credits : 68, score : 14 },
    {key: "q", credits : 1000, score : 102 },
    {key: "z", credits : 59, score : 352 }
  ]
}

Then the query you would write would be like this:

db.coll.find({services: {$elemMatch : {credits: {$lt: 50}}}});

result:

{ "_id" : ObjectId("4f0f2be07561bf94ea47eec4"), "services" : [  {   "key" : "a", "credits" : 100, "score" : 2000 }, { "key" : "b", "credits" : 200, "score" : 300 },    {   "key" : "c",    "credits" : 10,     "score" : 1300 } ] }

Upvotes: -4

Related Questions