我有一个使用两种模型的应用程序:电影和标签。这个想法是人们可以创建电影的记录并为其附加标签。电影通过 Movie.tags 属性引用一个或多个标签模型,该属性是一个包含相应标签的 ObjectId 的数组。
在客户端显示电影的属性时,显示标签的文本而不是标签的 ObjectId 是有意义的(请记住:Movie.tags 是 ObjectId 的数组)。我考虑了这个问题并得出结论,最好的方法是使用 getter 函数,这样当我检索 Movie 文档时,tags 属性的值就会从 ObjectIds 数组转换为相应标签名称的数组。
为此,我必须对数组 Movie.tags 中的每个 ObjectId 执行数据库查询。由于 db 查询是在 Mongoose 中异步完成的,因此我尝试使用Async 模块中的async.forEach()函数来实现 getter 函数。问题是在 async.forEach 函数的末尾没有返回最终值。
关于这个问题,我有两个问题:
- 鉴于我的总体目标,使用 getter 函数是解决此问题的最佳方法吗?
- 为什么 async.forEach() 无法返回更新后的数组?
来自模型.js
/**
* Mongo database models
*/
function defineModels(mongoose, async, fn) {
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
/**
* Model - Movie
*/
/**
* Getter function
*
* Gets tag text as well as tag ObjectId.
*/
function getTagNames(tags) {
var newArray = new Array();
async.forEach(
tags,
function(id, done) {
mongoose.models['Tag'].findOne({ _id: id }, function(err, doc) {
if (err) {
done(err);
}
else if (doc) {
newArray.push(doc);
done(null);
}
else {
console.log(doc);
// Just incase something weird like no document is found.
// Technically this condition should not occur in reality. But we
// put something here to catch it just in case.
done(new Error('No tag document found.'));
}
});
},
function(err) {
if (err) {
throw err;
}
console.log(newArray);
return newArray;
}
);
}
/**
* Define schema
*/
Movie = new Schema({
'name': String,
'machineFileName': String,
'originalFileName': String,
'size': Number,
'type': String,
'permanent': {
type: Boolean,
default: false
},
'dateUploaded': Date,
'amountUploaded': {
type: [],
default: 0
},
'viewed': Number,
'uid': String,
'flags': [],
'tags': {
type: Array,
get: getTagNames
}
}, { strict: true });
mongoose.model('Movie', Movie);
/**
* Model - Tag
*/
Tag = new Schema({
'title': { type: String, unique: true, sparse: true }
}, { strict: true });
mongoose.model('Tag', Tag);
fn();
}
exports.defineModels = defineModels;
检索文档:
/**
* View individual movie.
*/
exports.movie = function(req, res) {
var Movie = mongoose.model('Movie');
Movie.findById(req.params.id, function(err, doc) {
if (err) {
res.send('An error occured.', 500);
}
else {
console.log('View movie');
console.log(doc);
res.render('movie', {
locals: {
title: 'Watch Movie',
movie: doc
}
});
}
});
}