我对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天。
答案 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);
});
});