Javascript ExpressJS和Mongoose使用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

在我创建的网站上,用户可以输入不同的标签,并用逗号分隔。ExpressJS然后应该搜索它们是否存在。如果它们不存在,那么它应该为它们中的每一个创建一个对象。我有一个数组,正在使用for函数遍历它,但是,由于回调,只创建了一个对象。。。是否有可能根据阵列的长度一次创建多个对象

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": []
}