我有一个应用程序,它使用两个模型:电影和标签。我们的想法是,可以创建电影记录并为其附加标签。电影通过Movie.tags属性引用一个或多个Tag模型,该属性是包含相应标签的ObjectId的数组。
在客户端显示Movie的属性时,显示标记的文本而不是标记的ObjectId是有意义的(请记住:Movie.tags是ObjectIds的数组)。我想到了这个问题并得出结论,最好的方法是使用getter函数,这样当我检索Movie文档时,tags属性的值将从ObjectIds数组转换为相应标记名的数组。
为此,我必须为数组Movie.tags中的每个ObjectId执行db查询。由于db查询是在Mongoose中异步完成的,我尝试使用Async模块中的async.forEach()函数实现getter函数。问题是在async.forEach函数结束时没有返回最终值。
关于这个问题我有两个问题:
/**
* 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
}
});
}
});
}
答案 0 :(得分:0)
我认为你最好使tags
成为一个ObjectId refs数组,然后使用Mongoose的populate
在需要时用实际的标记对象填充它。
在Movie
架构中,tags
变为:
tags: [{ type: ObjectId, ref: 'Tag' }]
然后当您查询Movie
时:
Movie.findById(req.params.id).populate('tags').exec(function(err, doc) {
// doc.tags is now an array of Tag instances