将猫鼬查询结果存储在另一个猫鼬查询中
Posted
技术标签:
【中文标题】将猫鼬查询结果存储在另一个猫鼬查询中【英文标题】:Store mongoose Query result inside another mongoose query 【发布时间】:2017-05-08 04:04:46 【问题描述】:我对 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()
查询完成后尝试访问 traveler 数组时,我得到一个空响应,而当我 console.log()
数据在查询期间正确打印时,有人可以帮助我完成这个新的异步范式,我已经敲了 2 天了。
【问题讨论】:
res.json
必须进入async.forEach
回调。但我想这可以使用参考人口更容易解决,因为用户存在于 Travel 的 traveller
属性中。 OT:为什么这个方法是POST
?你显然没有改变任何数据?
我使用 post 是因为我需要从 post 请求中存在的 date 属性中获取数据。
【参考方案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);
);
);
【讨论】:
我能够通过您的回答完成它,只需一个修改我们需要在 async.foreach() 函数中的function(err)
中添加 callback()
,谢谢!
@VedantRathore 不错。我添加了缺少的callback()
。以上是关于将猫鼬查询结果存储在另一个猫鼬查询中的主要内容,如果未能解决你的问题,请参考以下文章