【问题标题】:MongoDB callback return issue for nested call嵌套调用的 MongoDB 回调返回问题
【发布时间】:2017-03-13 18:21:11
【问题描述】:

我正在尝试在我一直在处理的 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: [] } ]

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

已解决

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

【问题讨论】:

  • 主函数中需要queryExercise的结果??现在执行上述代码的错误是什么??
  • 我相信问题可能在这里"$exercises.drink_date";您的 Exercises 架构中没有 drink_date
  • 在我打字时很尴尬,出于某种原因,我正在考虑喝一杯。刚刚检查了我的源代码,它应该是goal_date。我已经修改了帖子。
  • 我找到了解决方案。 MongoDB 正在使用该集合的复数版本。纠正它就像一个魅力。非常感谢您的帮助。

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


【解决方案1】:

您应该能够使用聚合框架管道执行单个查询,即使用 $lookup$unwind$redact strong> 管道阶段通过 aggregate() 管道执行返回您想要的文档。

在以下示例中,$lookup 管道允许您对 user_id 字段上的另一个集合执行“左连接”,展平作为以下结果生成的文档数组使用 $unwind 进行连接,然后使用 $redact 过滤管道中的文档,这将使用 $$KEEP 返回与日期条件匹配的所有文档strong> 并以其他方式丢弃使用 $$PRUNE 系统变量:

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
            }
        }
    });
};

请记住,对于每个输入文档,$unwind 输出 n 文档,其中 n 是数组元素的数量,对于空数组可以为零,因此可能存在需要对文档进行分组 再次在 $redact 管道之后,因为每个目标可能会有 (n-x) 文档,其中 n 是在 $lookup 之后生成的 exercises 数组的长度而x$redact之后过滤掉的元素个数。


更新

作为上述的后续,要对文档进行分组并获得预期的输出,您需要一个最终的 $group 管道,该管道按 _id 键对文档进行分组,使用 $first 累加器运算符返回 goal_id 字段并使用 $push 累加器创建 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
            }
        }
    });
};

【讨论】:

  • 很好的回应,非常有帮助。对于未来,我有兴趣为每个目标返回多个练习 - 当前的实现是否可以轻松实现?
  • 是的,这应该是可能的。你有什么预期的输出?你介意用那个更新你的问题吗?
  • 我已经更新了我的答案,希望可以解决。让我知道票价如何。
  • chridam,再次感谢您的慷慨帮助。我玩过您提供的语法并遇到了问题。我已经更新了第一篇文章。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 2016-01-29
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
相关资源
最近更新 更多