如何按标准匹配子文档中的数组元素

时间:2016-12-08 07:47:20

标签: node.js mongodb mongoose mongodb-query aggregation-framework

我有以下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'
    },
    primarySkills: [
    {
        type: Schema.Types.ObjectId,
        ref: 'skills'
    }
],
});

SkillsSchema:

var SkillsSchema = new Schema({
    name: {
        type: String,
        required: true
    }
});

EmployeeDetailSchema数据按需保存,例如将特定技能分配给Employee时。保存EmployeeDetail文档后,相应的EmployeeDetailID将保存回EmployeeSchema employeeDetailsId

现在EmployeeSchemaEmployeeDetailSchema之间存在双向关系。

注意: 多个技能可以与Employee关联,并且它们作为ObjectID的数组存储在EmployeeDetails Schema中。

UseCase:

我想获取所有具有与之关联的特定技能的员工,技能将输入到Mongoose / Mongo查询。

说输入技能ID是1234然后我想要获取在EmployeeDetail中具有技能ID 1234的所有员工> PrimarySkills数组。

以下是我尝试使用Mongoose的方法:

EmployeeModel.aggregate([
    {
        $lookup: {
            from: 'employeedetails', 
            localField: 'employeeDetailsId',
            foreignField: '_id',
            as: 'details'
        }
    },
    {
        $match: { 
            $and: [
                { "details.primarySkills": { "$exists": true } },               
                { 
                    "details.primarySkills": { 
                        $in: [mongoose.Types.ObjectId(req.params.skillId)]                          
                    }
                }
            ]
        } 
    }
]).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);
});

结果:空数组。

我不知道哪里出错了,需要一些帮助。

2 个答案:

答案 0 :(得分:1)

我所遵循的糟糕的原创方法除了一个小错误外都很好。我应该使用req.query.skillId代替req.params.skillId

对于那些想知道不同的b / w查询和参数的人,请查看answer

这是最终解决方案,认为它可以帮助其他人:

EmployeeModel.aggregate([
    {
        $lookup: {
            from: 'employeedetails', 
            localField: 'employeeDetailsId',
            foreignField: '_id',
            as: 'details'
        }
    },
    {
        $match: { 
            $and: [
                { "details.primarySkills": { "$exists": true } },               
                { 
                    "details.primarySkills": { 
                        $in: [mongoose.Types.ObjectId(req.query.skillId)]                          
                    }
                }
            ]
        } 
    }
]).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);
});

答案 1 :(得分:0)

您可以采取的一种方法是先将$lookup应用于Skills模型上的EmployeeDetails模型,然后再对Employee模型进行查找

EmployeeDetails.aggregate([
    { "$match": { "primarySkills": req.query.skillId } },
    { "$unwind": "$primarySkills" }, // skip this pipeline step for MongoDB 3.4 and above
    {
        "$lookup": {
            "from": "skills",// ensure this is the correct collection name
            "foreignField": "_id",
            "localField": "primarySkills",
            "as": "skills"
        }
    },
    { "$unwind": "$skills" }
    {
        "$group": {
            "_id": "$_id",
            "employeeId": { "$first": "$employeeId" },
            "primarySkills": { "$push": "$skills" }
        }
    },
    {
        "$lookup": {
            "from": "employees",// ensure this is the correct collection name
            "foreignField": "_id",
            "localField": "employeeId",
            "as": "employee"
        }
    }
]).exec(callback);