如何通过Criteria + Mongoose / MongoDB查找子文档

时间:2016-12-01 07:31:43

标签: node.js mongodb mongoose nosql

以下是两个Mongoose模式:

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数据按需保存,例如将特定状态分配给Employee时。在这种情况下,一旦保存了EmployeeDetail文档,则相应的EmployeeDetailID将作为 employeeDetailsId

保存回EmployeeSchema。

现在EmployeeSchema和EmployeeDetailSchema之间存在双向关系。

UseCase:

我想获取所有标记为特定状态的员工。假设输入状态ID为1234,那么我想在EmployeeDetail文档中获取状态ID为1234的所有员工。

以下是我尝试使用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);
        });
};

虽然有员工被分配到某些状态,但返回的结果是空数组。我对Mongoose的查询方法是对吗?

1 个答案:

答案 0 :(得分:2)

您根据架构设计使用EmployeeDetailSchema引用employeeDetailsId。所以你不能直接比较参考模型字段而不填充。您应首先填充然后比较和过滤文档,或者用户aggregate功能可以实现您的目标。

可以试试这个:

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:字符串转换为 ObjectId req.params.statusId

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