嵌套调用

时间:2017-02-28 13:36:50

标签: javascript node.js mongodb mongoose mongodb-query

我正在尝试在我正在处理的API中放置一个嵌套的MongoDB调用。 API的目标是基于锻炼执行来更新人员目标。我目前的问题是尝试将锻炼事件纳入主要功能,以使我能够计算“完整性”。

我欢迎您就此问题发表任何意见。

大家好,

我试图在我一直在研究的API中放置一个嵌套的MongoDB调用.API的目标是根据运动执行更新人员目标。我目前的问题是尝试将运动事件纳入主要的 功能使我能够计算“完整性”。

我欢迎您就此问题发表任何意见。

module.exports.generateGoal = function(request, response) {

//User ID 
var user_id = new ObjectId(request.params.id);

//Goal Search
Goals.find({
    user_id: user_id,
    active_goal: true
}, function(err, goals) {
    if (err) {
        //Error: send error to user
        throw err
    } else {
        if (goals.length == 0) { //No goals, do nothing
            return response.json({
                success: true,
                msg: "No Goal"
            });
        } else { //User as goals, therefore pull in exercise

            for (i = 0; i < goals.length; i++) {
                //Looking to have exercise available here for computation
                queryExercise(user_id, goals[i].start_date, goals[i].end_date, function(result) {
                    //Exercise able to be accessed here
                    console.log(result)
                    return result
                });
            }
        }
    }
});
};

function queryExercise(user_id, start_date, end_date, callback) {
    ExerciseData.find({
        user_id: user_id,
        exercise_date: {
            $gte: start_date,
            $lt: end_date
        }
    }, function(err, result) {
        if (err) {
            console.log(err);
        } else if (result.length > 0) {
            callback(result);
        }
    });
}

编辑2:

我非常感谢下面的回复,这正是我所需要的。思考未来,任何目标都可以进行多次练习,这是获得类似输出的最佳方法:

    {
    _id: dfhdjds8348hhj8
    goal_id: 1
    exercises: { {
      exercise: 1,
      type: running
    },
    {
      exercise: 2,
      type: running
    }
  }
}.
{
    _id: ddhdjds8342hhj8
    goal_id: 2
    exercises: { {
      exercise: 1,
      type: jumping
    },
    {
      exercise: 2,
      type: rowing
    }
  }
}

编辑3:

在实现下面的新代码后,我注意到它无法返回正确的值。我想提供一些关于我使用的模态和语法的更多信息。

目标

var mongoose = require('mongoose');

// Define goal model schema
var GoalsSchema = new mongoose.Schema({
    user_id: {
        type: mongoose.Schema.Types.ObjectId,
        required: true
    },
    active_goal: Boolean,
    goal_id: Number,
    start_date: Date,
    end_date: Date
}, {
    timestamps: true
});

// Export user model
module.exports = mongoose.model('Goals', GoalsSchema);

练习数据

var mongoose = require('mongoose');

// Define user model schema
var exercisesSchema = new mongoose.Schema({
    user_id: {
        type: mongoose.Schema.Types.ObjectId,
        required: true
    },
    exercise_date: Date,
    exercise_type: String  
}, {
    timestamps: true
});

// Export user model
module.exports = mongoose.model('exercises', exercisesSchema);

我在代码中使用的语法如下,不是我为使其正常工作而必须进行的其他更改。

module.exports.generateGoal = function(request, response) {

    //User ID
    var user_id = new ObjectId(request.params.id); //User ID

    //Goal query
    Goals.aggregate([{
                "$match": {
                    "user_id": user_id,
                    "active_goal": true
                }
            },
            {
                "$lookup": {
                    "from": "exercises",
                    "localField": "user_id",
                    "foreignField": "user_id",
                    "as": "exercises"
                }
            },
            {
                "$unwind": {
                    "path": "$exercises",
                    "preserveNullAndEmptyArrays": true
                }
            },
            {
                "$redact": {
                    "$cond": [{
                            "$and": [{
                                    "$gte": ["$exercises.exercise_date", "$exercises.start_date"]
                                },
                                {
                                    "$lte": ["$exercises.exercise_date", "$exercises.end_date"]
                                }
                            ]
                        },
                        "$$KEEP",
                        "$$PRUNE"
                    ]
                }
            },
            {
                "$group": {
                    "_id": "$_id",
                    "goal_id": {
                        "$first": "$goal_id"
                    },
                    "exercises": {
                        "$push": "$exercises"
                    }
                }
            }
        ],
        function(err, goalOut) {
            console.log(goalOut)
            if (err) {
                //Error: send error to user
                throw err
            } else {
                if (goalOut.length == 0) { //No goals, do nothing
                    return response.json({
                        success: true,
                        msg: "No Goal",
                        statusCode: 0,
                        payload: 'na'
                    });
                } else { //User as goals + matching exercise
                    //console.log(goals);

                    return response.json({
                        success: true,
                        msg: "Goals",
                        payload: goalOut
                    });
                }
            }
        });
};

其中输出以下内容:

[ { _id: 58c3e0b1c8a467055d900595, goal_id: 1, exercises: [] },
  { _id: 58c3e0adc8a467055d900594, goal_id: 2, exercises: [] } ]

正如您所看到的,练习数据实际上是一个空数组,尽管在下面的原始帖子中存在数据。

解决

我忘了注意收集名称的脉动

1 个答案:

答案 0 :(得分:1)

您应该能够使用聚合框架管道执行单个查询,即使用 $lookup $unwind { {3}} 管道阶段,可通过 $redact 管道执行返回所需的文档。

在以下示例中, aggregate() 管道允许您对user_id字段上的其他集合执行“左连接”,展平生成的文档数组与 $lookup 结合使用,然后使用 $unwind 过滤管道中的文档,该文件将返回与日期条件匹配的所有文档 $redact ,否则使用 $$KEEP 系统变量弃用:

module.exports.generateGoal = function(request, response) {

    //User ID 
    var user_id = new ObjectId(request.params.id);

    //Goal query
    Goals.aggregate([
        { "$match": { "user_id": user_id, "active_goal": true } },
        {
            "$lookup": {
                "from": "exercises",
                "localField": "user_id",
                "foreignField": "user_id",
                "as": "exercises"
            }
        },
        { "$unwind": "$exercises" },
        {
            "$redact": {
                "$cond": [
                    {
                        "$and": [
                            { "$gte": ["$exercises.exercise_date", "$start_date"] },
                            { "$lt": ["$exercises.exercise_date", "$end_date"] }
                        ]
                    },
                    "$$KEEP",
                    "$$PRUNE"
                ]
            }
        }
    ], function(err, goals) {
        if (err) {
            //Error: send error to user
            throw err
        } else {
            if (goals.length == 0) { //No goals, do nothing
                return response.json({
                    success: true,
                    msg: "No Goal"
                });
            } else { //User as goals + matching exercise
                console.log(goals);
                return goals
            }
        }
    });
};

请注意,对于每个输入文档, $$PRUNE 输出n个文档,其中n是数组元素的数量,对于空数可以为零数组,因此可能需要对文档进行分组 再次在 $unwind 管道之后,每个目标可能会有(n-x)个文档,其中nexercises数组的长度> $redactx $lookup 之后滤出的元素数。

更新

作为上述内容的后续行动,要对文档进行分组并获得预期的输出,您需要一个最终的 $redact 管道,按_id键对文档进行分组,使用 $group 累加器运算符返回goal_id字段,并使用 $first 累加器创建exercises数组。以下管道演示了这一点:

module.exports.generateGoal = function(request, response) {

    //User ID 
    var user_id = new ObjectId(request.params.id);

    //Goal query
    Goals.aggregate([
        { "$match": { "user_id": user_id, "active_goal": true } },
        {
            "$lookup": {
                "from": "exercises",
                "localField": "user_id",
                "foreignField": "user_id",
                "as": "exercises"
            }
        },
        { "$unwind": "$exercises" },
        {
            "$redact": {
                "$cond": [
                    {
                        "$and": [
                            { "$gte": ["$exercises.exercise_date", "$start_date"] },
                            { "$lt": ["$exercises.exercise_date", "$end_date"] }
                        ]
                    },
                    "$$KEEP",
                    "$$PRUNE"
                ]
            }
        },
        {
            "$group": {
                "_id": "$_id",
                "goal_id": { "$first": "$goal_id" },
                "exercises": { "$push": "$exercises" }
            }
        }
    ], function(err, goals) {
        if (err) {
            //Error: send error to user
            throw err
        } else {
            if (goals.length == 0) { //No goals, do nothing
                return response.json({
                    success: true,
                    msg: "No Goal"
                });
            } else { //User as goals + matching exercise
                console.log(goals);
                return goals
            }
        }
    });
};