Ed .
Ed .

Reputation: 6403

Find results with a certain number of fields in my MongoDB subdocument

I would like to query a subdocument where results must have all fields specified and no others. Is this possible? And if so how?

For example:

I want a query like this:

db.users.find({ 
    "pref.no_popup": true, 
    "pref.font_large": false, 
    "pref": { "$size", 2 }});

To match this:

{
  "user": "Ed",
  "pref": {
    "no_popup": true,
    "font_large": false
  }
}

But not this:

{
  "user": "James",
  "pref": {
    "no_popup": true,
    "font_large": false,
    "font_red": true
  }
}

I realise the $size operator is designed for arrays, so how can I do something similar for subdocuments?

Note that I did try not using a dot notation to query for exact field presence but then I had issues with ordering.

Upvotes: 3

Views: 150

Answers (4)

Malcolm Murdoch
Malcolm Murdoch

Reputation: 1085

I think you're going to have to use a mapReduce...

Not ideal, but should solve the problem.

mapper=function(){ for (key in this.pref){
  emit(this._id, {'count':1}); \\assume your user id is called _id
  }
}
reducer=function(k,v){ 
  counter=0; 
  for (i=0;i<v.length;i++){
    counter+=v[i].count;
  }
  return {'count':counter}
 }

This should give you a collection with people's IDs and the number of prefs that have been set

Upvotes: 0

Ivan.Srb
Ivan.Srb

Reputation: 1851

If your have many properties that you do not wont to match, and only two that wont, you could try something like this to solve order problem (as upgrade to Andrei answer):

db.users.find({ $or: [
"pref" : {
    "no_popup" : true,
    "font_large" : false
},
"pref" : {       
    "font_large" : false,
    "no_popup" : true
} ] });

Upvotes: 1

rubenfa
rubenfa

Reputation: 851

Have you checked $exists operator?

db.users.find({ 
    "pref.font_red" : {"$exists":false}
});

Upvotes: 1

Andrei Nicusan
Andrei Nicusan

Reputation: 4623

There is this "Exact match on subdocument" scenario. Here, search in page for the quoted text.

I think that your query should be:

db.users.find({ 
    "pref" : {
        "no_popup" : true,
        "font_large" : false
    } });

Upvotes: 1

Related Questions