Javascript ExpressJS和Mongoose使用for函数多次创建
在我创建的网站上,用户可以输入不同的标签,并用逗号分隔。ExpressJS然后应该搜索它们是否存在。如果它们不存在,那么它应该为它们中的每一个创建一个对象。我有一个数组,正在使用for函数遍历它,但是,由于回调,只创建了一个对象。。。是否有可能根据阵列的长度一次创建多个对象Javascript ExpressJS和Mongoose使用for函数多次创建,javascript,node.js,mongodb,express,mongoose,Javascript,Node.js,Mongodb,Express,Mongoose,在我创建的网站上,用户可以输入不同的标签,并用逗号分隔。ExpressJS然后应该搜索它们是否存在。如果它们不存在,那么它应该为它们中的每一个创建一个对象。我有一个数组,正在使用for函数遍历它,但是,由于回调,只创建了一个对象。。。是否有可能根据阵列的长度一次创建多个对象 for (i=0;i<postTopics.length;i++) { var postTopic = postTopics[i], postTopicUrl = postTopic.toStr
for (i=0;i<postTopics.length;i++) {
var postTopic = postTopics[i],
postTopicUrl = postTopic.toString().toLowerCase().replace(' ', '-');
Topic.findOne({ "title": postTopics[i] }, function (err, topic) {
if (err) throw err;
if (!topic) {
Topic.create({
title: postTopic,
url: postTopicUrl
}, function (err, topic) {
if (err) throw err;
res.redirect('/');
});
}
});
}
for(i=0;i尝试
$npm安装异步
首先,我们创建一个名为topicQueries
的对象,并为postTopics
数组中的每个postTopics
标题附加一个查询函数。然后,我们将完成的topicQueries
对象传递给async.parallel
,该对象将运行每个查询并将结果收集到results
对象中。
results
对象最终是一个简单的对象哈希,每个postTopic
标题都是键,值是来自DB的结果。if(results[postTopic])return;
如果results
在postTopic
键下没有文档,则返回该行。这意味着,它下面的代码仅在DB没有返回具有该标题的主题时运行。如果没有匹配的主题,则我们向createQueries
数组添加一个查询函数
我们不希望您的页面在其中一个新主题完成保存后重定向。我们希望等到您的所有创建查询完成,所以我们再次使用async.parallel
,但这次我们使用数组而不是对象哈希,因为我们不需要将结果绑定到任何内容。当您将数组传递给async时。parallel
参数results
也将是一个包含每个查询结果的数组,尽管在本例中我们并不真正关心结果,只是没有抛出错误。如果parallel
函数完成,并且没有err
参数,则所有主题都成功完成创建,并且我们最终可以将用户重定向到新页面
PS-如果您遇到过类似的情况,除了后续的每个查询都需要前面的查询中的数据外,请签出:)
如果您真的想查看是否已经存在,并避免在重复项上出现错误,那么该方法已经接受了一个列表。您似乎并不关心如何创建响应文档,因此只需检查存在的文档并发送新文档即可
因此,使用“先查找”,依次运行任务<代码>异步.瀑布
只是为了让缩进爬行变得更漂亮:
// Just a placeholder for your input
var topics = ["A Topic","B Topic","C Topic","D Topic"];
async.waterfall(
[
function(callback) {
Topic.find(
{ "title": { "$in": topics } },
function(err,found) {
// assume ["Topic B", "Topic D"] are found
found = found.map(function(x) {
return x.title;
});
var newList = topics.filter(function(x) {
return found.indexOf(x) == -1;
});
callback(err,newList);
}
);
},
function(newList,callback) {
Topic.create(
newList.map(function(x) {
return {
"title": x,
"url": x.toString().toLowerCase().replace(' ','-')
};
}),
function(err) {
if (err) throw err;
console.log("done");
callback();
}
);
}
]
);
您可以将“url”生成移动到“预”保存模式挂钩。但是,如果您真的不需要验证规则,请选择“批量API”操作,前提是您的目标MongoDB和mongoose版本足够新,可以支持此操作,这意味着您可以获得底层驱动程序的句柄:
// Just a placeholder for your input
var topics = ["A Topic","B Topic","C Topic","D Topic"];
async.waterfall(
[
function(callback) {
Topic.find(
{ "title": { "$in": topics } },
function(err,found) {
// assume ["Topic B", "Topic D"] are found
found = found.map(function(x) {
return x.title;
});
var newList = topics.filter(function(x) {
return found.indexOf(x) == -1;
});
callback(err,newList);
}
);
},
function(newList,callback) {
var bulk = Topic.collection.initializeOrderedBulkOp();
newList.forEach(function(x) {
bullk.insert({
"title": x,
"url": x.toString().toLowerCase().replace(' ','-')
});
});
bulk.execute(function(err,results) {
console.log("done");
callback();
});
}
]
);
这是对服务器的一次写入操作,当然,所有插入操作实际上都是按顺序完成的,并检查是否有错误
否则,只需挂起重复的错误并作为“无序操作”插入,如果需要,请在以下步骤后检查“非重复”错误:
// Just a placeholder for your input
var topics = ["A Topic","B Topic","C Topic","D Topic"];
var bulk = Topic.collection.initializeUnorderedBulkOp();
topics.forEach(function(x) {
bullk.insert({
"title": x,
"url": x.toString().toLowerCase().replace(' ','-')
});
});
bulk.execute(function(err,results) {
if (err) throw err;
console.log(JSON.stringify(results,undefined,4));
});
结果中的输出类似于以下内容,指示“重复”错误,但不会“抛出”错误,因为在本例中未设置此错误:
{
"ok": 1,
"writeErrors": [
{
"code": 11000,
"index": 1,
"errmsg": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.topic.$title_1 dup key: { : \"B Topic\" }",
"op": {
"title": "B Topic",
"url": "b-topic",
"_id": "53b396d70fd421057200e610"
}
},
{
"code": 11000,
"index": 3,
"errmsg": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.topic.$title_1 dup key: { : \"D Topic\" }",
"op": {
"title": "D Topic",
"url": "d-topic",
"_id": "53b396d70fd421057200e612"
}
}
],
"writeConcernErrors": [],
"nInserted": 2,
"nUpserted": 0,
"nMatched": 0,
"nModified": 0,
"nRemoved": 0,
"upserted": []
}
请注意,使用本机收集方法时,需要注意已建立连接。mongoose方法将“排队”直到建立连接,但这些方法不会。更多的是测试问题,除非这可能是第一个执行的代码
希望这些批量操作的版本很快会在MongooseAPI中公开,但一般的后端功能确实取决于服务器上是否有MongoDB 2.6或更高版本。一般来说,这将是最好的处理方法
当然,除了最后一个不需要这个的示例之外,您可以通过调用该库下存在的“filter”、“map”和“forEach”版本来完全“异步”。这可能不是一个真正的问题,除非你提供了很长的输入列表
节点本机驱动程序手册中介绍了方法和步骤。另请参阅主手册,了解。的一般说明。与其一次查找一个主题,为什么不查询所有主题,并循环查看该结果?您能给我举个例子吗?不管怎样,我都会得到相同的结果,因为创建主题有一个回调函数?如果是这样,您可以只进行一次DB调用来创建并忽略保存findOne调用的重复错误。其次,当您在create调用的第一个响应上使用重定向进行响应时,您应该等待所有异步mongo请求都响应。我的回答假设
title
在您的模型中没有唯一的索引。正如adamK所指出的,如果您的主题文档的标题字段上有一个唯一的索引,那么您可以简单地调用topic.create
为每个postTopic
创建一个,并在它抱怨重复条目时忽略错误。然后,您可以只使用一次async.parallel
,等待所有创建查询完成。请记住,如果试图忽略错误,您可能必须自己调用cb
,因为如果将err
传递给async,它将中止并立即将错误传递给result函数。
{
"ok": 1,
"writeErrors": [
{
"code": 11000,
"index": 1,
"errmsg": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.topic.$title_1 dup key: { : \"B Topic\" }",
"op": {
"title": "B Topic",
"url": "b-topic",
"_id": "53b396d70fd421057200e610"
}
},
{
"code": 11000,
"index": 3,
"errmsg": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.topic.$title_1 dup key: { : \"D Topic\" }",
"op": {
"title": "D Topic",
"url": "d-topic",
"_id": "53b396d70fd421057200e612"
}
}
],
"writeConcernErrors": [],
"nInserted": 2,
"nUpserted": 0,
"nMatched": 0,
"nModified": 0,
"nRemoved": 0,
"upserted": []
}