7

I have a Person object in mongoose, and that person object has multiple things (each thing has a unique ID).

person1 = {
  things[{id: 1, name: 'one'},{id:2, name: 'two'}]
}
person2 = {
  things[{id: 3, name: 'three'},{id:4, name: 'four'}]
}

then query:

Person.findOne({'things.id': 2},{'things.$': 1}, function(err, person) { ...

This works great but I am searching through all Person objects (which there could be a lot of). In this case I know the id of the Person I need and some unique id of a 'thing'. Its probably a lot faster to get the Person by id:

Person.findById(personId, function(err, person) { ...

Then loop over all the things to find the right one:

var thing
person.things.forEach(function(t) {
  if (t.id == thingId) {
    thing = t;
  }
});

What I am wondering is if there is a better way. I.E. can I query the Person collection by id to get just one Person then filter out just the thing I am looking for (without the ugly loop)?

2
  • 9
    What does things.$ mean? What does the $ refer to/do? Commented Dec 31, 2013 at 15:14
  • 3
    The $ is a positional operator. You can find more details about it in the Mongo docs ;) Commented Oct 23, 2014 at 13:38

1 Answer 1

19

You can include both id terms in a single query and the single element projection will still work:

Person.findOne({_id: personId, 'things.id': 2}, {'things.$': 1}, 
    function(err, person) { ...
Sign up to request clarification or add additional context in comments.

4 Comments

So that will query on Person first (which should be fast), then on a specific thing for that person? That is awesome, thanks!
So does this mean that the person object will be returned with only one element in the things array, that being the thing we are looking for in the query?
Nice. I am looking now for a way to do this but with findOneAndUpdate, because I need to update only a specific element of a document array. Do you have any ideas on how to accomplish this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.