JonRed
JonRed

Reputation: 2981

How to find a document by data within an array of sub documents

I'm struggling to find the right syntax for my query.

I have the following schema

var Person = mongoose.Schema({
    name: String,
    cars: [{type: Schema.Types.ObjectId, ref: 'Car'}] -- Note this is an array
});

I want to write a query that effectively tells me all the people that own a red car.

I think I want something like:

Person.find().populate('cars').match({colour:red}).exec(function(err, models) {....

But I can't find any documentation to back this up. Any tips appreciated.

EDIT:

This code is getting close, but still no there

Person.find()
    .populate({path: 'cars', match: {colour: "red"}})
    .exec(function (err, Persons) {

The reason being, it returns all 'Person' records and only populates the 'cars' array for those it matches in the populate function. As a result I get lots of Person.cars.length === 0 in there.

If I add a modification to the find:

Person.find()
    .populate({path: 'cars', match: {colour: "red"}})
    .where({'cars' : {$not: {$size:  0}}}
    .exec(function (err, Persons) {

This also has no affect; I'm assuming the where runs before the populate. Breaking the query up into separate lines has no affect either.

Upvotes: 0

Views: 49

Answers (2)

JohnnyHK
JohnnyHK

Reputation: 312129

It's typically more efficient to flip these type of queries around and first find the _ids of all the red cars and then find the people with those cars:

Car.find({colour: 'red'}, function(err, cars) {
    var carIds = cars.map(function(car) {
        return car._id;
    });
    Person.find({cars: {$in: carIds}}, function(err, persons) {...});
});

Upvotes: 1

A.B
A.B

Reputation: 20445

try this , break it up in this manner

   var q = Person.find();
   q.populate('cars').match({color:red}).exec(function(err, models) {....}

or this , with thee same effect

      var q = Person.find();
   q.populate({path: 'cars', match: { color:red}}).exec(function(err, models) {....}

then you have to filter for whether car is present or not

like

.exec(function(err, models){
   models= docs.filter(function(model){
     return doc.cars.length;
   })
   // do stuff with models
});

Upvotes: 1

Related Questions