我正在创建一个包含标签的帖子的简单博客。
var postSchema = new Schema ({
title: { type: String, required: true },
content: { type: String, required: true },
tags: [{ type: Schema.Types.ObjectId, ref: 'Tag' }]
});
当用户发布帖子时,我会将标签作为标签名称数组。我如何循环浏览这些标签并创建它们并在首次保存时将它们添加到帖子中?
我试过这个:
var post = Post({
title: data.title,
content: data.content
});
data.tags.forEach(function(name) {
Tag.findOrCreate({ name: name }, function(err, tag, created) {
post.tags.push(tag);
post.save(function(err) {
if (err) throw err;
console.log('Post saved!');
});
});
});
但这迫使我为每个标签再次保存帖子。有没有办法只保存一次?
答案 0 :(得分:2)
嗯,你当然可以只调用.save()
一次,只需在处理循环后将其移动到。但是当然因为这里所有的调用都是“异步”的,所以你需要更好地控制它,以便你知道每个操作的回调何时完成:
在这里使用async
库作为帮助:
var post = Post({
title: data.title,
content: data.content
});
async.eachLimit(data.tags, 5, function(name,callback) {
Tag.findOrCreate({ "name": name },function(err,tag) {
if (err) callback(err);
post.tags.push(tag);
callback();
});
},function(err) {
if (err) throw err; // or some handling as all errors come here
post.save(function(err,post) {
})
});
因此async.eachLimit
允许在每次处理完的数组元素时触发“回调”。 “限制”部分实际上确保只有许多操作同时运行,因此您不会吃掉堆栈或可用的连接。
当处理列表中的所有项目并返回回调函数时,执行最终块,因此当创建或找到所有项目并将相应的数据推送到阵列准备保存时。
以同样的方式,如果在该循环中发生任何“错误”,则执行被传递到该最终块,以便在一个地方处理所有错误操作。