2016-12-22 3 views
2

Я довольно новичок в nodeJs и mongodb. У меня возникли проблемы с запросом объектов мангуста. У меня есть 2 моделиМагазин mongoose Результат запроса в другом запросе mongoose

модель Пользователь:

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() запрос завершен, я получаю пустой или onse, тогда как когда I console.log() данные корректно печатаются во время запроса, может кто-то помочь мне в этой новой асинхронной парадигме, я уже два дня стучал головой.

+0

'Рез .json' должен войти в обратный вызов 'async.forEach'. Но я думаю, что это можно было бы решить гораздо проще с использованием ссылочной совокупности, поскольку пользователи присутствуют в свойстве Traveller' Travel. OT: Почему этот метод «POST»? Вы, очевидно, не изменяете никаких данных? – qqilihq

+0

Я использую пост, потому что мне нужно получить данные из свойства даты, которое присутствует в почтовом запросе. –

ответ

1

Добавить API async.series, который будет запускать по одной функции за один раз, дожидаясь, пока он вызовет обратный вызов своей задачи, и, наконец, когда все задачи будут завершены, он запустит 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); 
    }); 
}); 
+1

Мне удалось завершить его с помощью одной модификации , нам нужно добавить 'callback()' in 'function (err)' в функцию async.foreach(), спасибо! –

+0

@VedantRathore Ницца. Я добавил отсутствующий 'callback()'. – chridam