将mongoose查询结果存储在另一个mongoose查询中

时间:2016-12-22 13:48:36

标签: node.js mongodb asynchronous mongoose

我对nodeJs和mongodb相当新。我在查询猫鼬物体方面遇到了一些问题。我有2个型号

用户模型:

var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
var gravatar = require('gravatar');
var Schema = mongoose.Schema;
var SendSchema = require('./Send').schema;
var TravelSchema = require('./Travel').schema;

var UserSchema = new Schema({
    name: String,
    email:{type: String, required: true, unique:true},
    phone: {type: String, required: true, unique:true},
    password: {type:String,required:true},
    token: String,
    is_admin : Boolean,
    sendings : [SendSchema],
    travels : [TravelSchema],
    created_at : Date,
    updated_at : Date,
    image_url: String
})

UserSchema.pre('save',function(next){
    var user = this;
    if (this.isModified('password')||this.isNew){
        bcrypt.genSalt(10,function(err,salt){
            if(err){
                return next(err);
            }
            bcrypt.hash(user.password,salt,function(err,hash){
                if(err){
                    return next(err);
                }
                user.password = hash;
                next();
            });
        });
    } else {
        return next();
    }
});

UserSchema.pre('save', function(next) {
    var currentDate = new Date();
    this.updated_at = currentDate;
    if (!this.created_at)
    this.created_at = currentDate;
    next();
});


UserSchema.methods.comparePassword = function (pw,cb) {
    bcrypt.compare(pw,this.password,function(err,isMatch){
        if(err){
            return cb(err);
        }
        cb(null,isMatch);
    });
};


module.exports = mongoose.model('User',UserSchema);

和旅行模式:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var TravelSchema = new Schema({
    travelling_from:String,
    travelling_to:String,
    amount:String,
    date:Date,
    created_at: Date,
    updated_at: Date,
    traveller : {type:Schema.Types.ObjectId ,ref:'User'}
});

TravelSchema.pre('save', function(next) {
    var currentDate = new Date();
    this.updated_at = currentDate;
    if (!this.created_at)
    this.created_at = currentDate;
    next();
});

module.exports = mongoose.model('Travel',TravelSchema);

现在使用快递路线我查询像这样的猫鼬模型:

router.post('/travellers',passport.authenticate('jwt',{session:false}), function(req, res, next) {
    var pickup_location = req.body.pickup_location;
    var delivery_location = req.body.delivery_location;
    var date = req.body.date;
    var sender = req.user._id;
    var senders = [];
    var travellers =[];

    Travel.find({'date':date},function (err,travels) {
        if(err) console.error(err.message);;
        async.forEach(travels,function (travel,callback) {
            User.findById(travel.traveller,function (err,user) {
                if(err) throw err;
                data = {
                    name:user.name,
                    email:user.email,
                    phone:user.phone,
                    image_url:user.image_url,
                    type:'traveller'
                };
                console.log(data);
                travellers.push(data);
                callback();
            });
        },function (err) {
            if(err) console.error(err.message);;
        });
    });
    console.log(travellers);
    res.json(travellers);
});

当我在res.json()查询完成后尝试访问旅行者数组时,我得到一个空响应,而当我console.log()数据在查询期间正确打印时,有人可以帮助我通过这种新的异步范式,我现在已经敲了2天。

1 个答案:

答案 0 :(得分:1)

添加async.series API,它将一次运行一个函数,等待它调用其任务回调,最后当所有任务完成后,它将运行callback(最终回调)。

例如:

router.post('/travellers',
    passport.authenticate('jwt', { "session": false }), function(req, res, next) {
    var pickup_location = req.body.pickup_location;
    var delivery_location = req.body.delivery_location;
    var date = req.body.date;
    var sender = req.user._id;
    var locals = {
        travellers: [],
        senders: []
    };

    async.series([
        // Load travels first
        function(callback) {
            Travel.find({ "date": date }, function (err, travels) {
                if (err) return callback(err);
                locals.travels = travels;
                callback();
            });
        },
        // Load users (won't be called before task 1's "task callback" has been called)
        function(callback) {
            async.forEach(locals.travels, function (travel, callback) {
                User.findById(travel.traveller, function (err, user) {
                    if (err) return callback(err);
                    data = {
                        "name": user.name,
                        "email": user.email,
                        "phone": user.phone,
                        "image_url": user.image_url,
                        "type": "traveller"
                    };
                    console.log(data);
                    local.travellers.push(data);
                    callback();
                });
            }, function (err) {
                if (err) return callback(err);
                            callback();
            });
        }
    ], function(err) { /* This function gets called after 
          the two tasks have called their "task callbacks" */
        if (err) return next(err);
        //Here locals will be populated with `travellers` and `senders`
        //Just like in the previous example
        console.log(locals);
        console.log(locals.travellers);
        res.json(locals.travellers);
    });
});

另一种方法是在聚合框架中使用 $lookup 运算符,您可以在其中运行如下聚合操作:

router.post('/travellers',
    passport.authenticate('jwt', {session: false }), function(req, res, next) {
    var pickup_location = req.body.pickup_location;
    var delivery_location = req.body.delivery_location;
    var date = req.body.date;

    Travel.aggregate([
        { "$match": { "date": date } },
        {
            "$lookup": {
                "from": "users",
                "localField": "traveller",
                "foreignField": "_id",
                "as": "traveller"
            }
        },
        { "$unwind": "$traveller" },
        {
            "$group": {
                "_id": null,
                "travellers": { 
                    "$push": {
                        "name": "$traveller.name",
                        "email": "$traveller.email",
                        "phone": "$traveller.phone",
                        "image_url": "$traveller.image_url",
                        "type": "traveller"
                    }               
                }
            }
        }
    ], function(err, results) { 
        if (err) return next(err);
        console.log(results);
        console.log(results[0].travellers);
        res.json(locals[0].travellers);
    });
});