BeingSuman
BeingSuman

Reputation: 3323

How to find Sub-Documents by Criteria + Mongoose / MongoDB

Following are two Mongoose schemas :

EmployeeSchema :

var EmployeeSchema = new Schema({
    name : String,
    employeeDetailsId: {
        type: Schema.Types.ObjectId,
        ref: 'employeedetails'
    }
});

EmployeeDetailSchema :

var EmployeeDetailSchema = new Schema({
    employeeId: {
        type: Schema.Types.ObjectId,
        ref: 'employee'
    },
    statusId: {
        type: Schema.Types.ObjectId,
        ref: 'status'
    }
});

EmployeeDetailSchema data gets saved on demand, like when a particular status is assigned to Employee. In that case, once EmployeeDetail document is saved then corresponding EmployeeDetailID is saved back to EmployeeSchema as employeeDetailsId

Now there is bi-directional relationship between EmployeeSchema and EmployeeDetailSchema.

UseCase :

I want to fetch all Employees who are tagged with particular status. Say input Status ID is 1234 then i want to fetch all employees whose status id is 1234 in EmployeeDetail document.

Following is the approach which i tried using Mongoose :

exports.getEmployeesByStatus = function (req, res) {
    console.log('Status ID : ' + req.query.statusId);

    EmployeeModel.find({'employeeDetailsId.statusId': {$eq: mongoose.Types.ObjectId(req.params.statusId)}})
        .exec(function (err, result) {
            if (err)res.send('400', {message: 'Unable to fetch employees data by status. Please try again later'});

            res.jsonp(result);
        });
};

Result that is returned is empty array though there are employees who are assigned to some statuses. Is my querying approach with Mongoose right ?

Upvotes: 0

Views: 1172

Answers (1)

Shaishab Roy
Shaishab Roy

Reputation: 16805

You are using reference of EmployeeDetailSchema for employeeDetailsId according to your schema design. so you can't directly compare reference model field without populate. you should populate first then compare and filter documents or can user aggregate function achieve your goal.

can try this one:

EmployeeModel.aggregate([
      {$lookup: {from: 'employeedetails', localField: 'employeeDetailsId',foreignField: '_id',as: 'details'}},
      {$match: { $and:[{ "details.statusId": { "$exists": true } },{"details.statusId": req.params.statusId}]} }
    ]).exec(function (err, result) {
            if (err) return res.send('400', {message: 'Unable to fetch employees data by status. Please try again later'});

            return res.jsonp(result);
        });

N.B: convert String to ObjectId the value of req.params.statusId

{$match: {$and: [{"details.statusId": {"$exists": true}}, {"details.statusId": mongoose.Types.ObjectId(req.params.statusId)}]}}

Upvotes: 2

Related Questions