javascript - ExpressJS 和 Mongoose 使用 for 函数多次创建

标签 javascript node.js mongodb express mongoose

在我创建的网站上,用户可以输入不同的标签并用逗号分隔它们。然后 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('/');
            });
        }
    });
}

最佳答案

试试 async.parallel .

$ npm install async

// Get the async module so we can do our parallel asynchronous queries much easier.
var async = require('async');

// Create a hash to store your query functions on.
var topicQueries = {};

// Loop through your postTopics once to create a query function for each one.
postTopics.forEach(function (postTopic) {
    // Use postTopic as the key for the query function so we can grab it later.
    topicQueries[postTopic] = function (cb) {
        // cb is the callback function passed in by async.parallel. It accepts err as the first argument and the result as the second.
        Topic.findOne({ title: postTopic }, cb);
    };
});

// Call async.parallel and pass in our topicQueries object.
// If any of the queries passed an error to cb then the rest of the queries will be aborted and this result function will be called with an err argument.
async.parallel(topicQueries, function (err, results) {
    if (err) throw err;

    // Create an array to store our Topic.create query functions. We don't need a hash because we don't need to tie the results back to anything else like we had to do with postTopics in order to check if a topic existed or not.
    var createQueries = [];

    // All our parallel queries have completed.
    // Loop through postTopics again, using postTopic to retrieve the resulting document from the results object, which has postTopic as the key.
    postTopics.forEach(function (postTopic) {
        // If there is no document at results[postTopic] then none was returned from the DB.
        if (results[postTopic]) return;

        // I changed .replace to use a regular expression. Passing a string only replaces the first space in the string whereas my regex searches the whole string.
        var postTopicUrl = postTopic.toString().toLowerCase().replace(\ \g, '-');

        // Since this code is executing, we know there is no topic in the DB with the title you searched for, so create a new query to create a new topic and add it to the createQueries array.
        createQueries.push(function (cb) {
            Topic.create({
                title: postTopic,
                url: postTopicUrl
            }, cb);
        });
    });

    // Pass our createQueries array to async.parallel so it can run them all simultaneously (so to speak).
    async.parallel(createQueries, function (err, results) {
        // If any one of the parallel create queries passes an error to the callback, this function will be immediately invoked with that err argument.
        if (err) throw err;

        // If we made it this far, no errors were made during topic creation, so redirect.
        res.redirect('/');
    });
});

首先,我们创建一个名为 topicQueries 的对象,并为 postTopics 数组中的每个 postTopic 标题附加一个查询函数。然后,我们将完成的 topicQueries 对象传递给 async.parallel,它将运行每个查询并将结果收集到 results 对象中。

results 对象最终是一个简单的对象哈希,其中每个 postTopic 标题作为键,值是来自数据库的结果。如果 results 在该 postTopic 键下没有文档,则 if (results[postTopic]) return; 行将返回。这意味着,只有当数据库没有返回具有该标题的主题时,它下面的代码才会运行。如果没有匹配的主题,那么我们将查询函数添加到 createQueries 数组中。

我们不希望您的页面在其中一个新主题完成保存后重定向。我们想要等到所有创建查询完成,因此我们再次使用async.parallel,但这次我们使用数组而不是对象哈希,因为我们不需要绑定(bind)结果对任何事情。当您将数组传递给 async.parallel 时,results 参数也将是一个包含每个查询结果的数组,尽管我们并不真正关心此中的结果例如,只是没有抛出错误。如果parallel函数完成并且没有err参数,那么所有主题都成功创建,我们最终可以将用户重定向到新页面。

PS - 如果您遇到类似的情况,但每个后续查询都需要之前查询中的数据,请查看 async.waterfall :)

关于javascript - ExpressJS 和 Mongoose 使用 for 函数多次创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24521741/

相关文章:

javascript - 如何有条件地将名称附加到字符串?

javascript - 如何使用 JQuery 追加 ajax 成功响应后聚焦到 div

node.js - 如何在 Express 中访问 mongoose 虚拟对象

node.js - Jest : tests can't fail within setImmediate or process. nextTick 回调

mongodb - MongoDB聚合框架如何统计满足一定条件的组数?

MongoDB $oid 与 ObjectId

windows - 如何设置SSH隧道以连接到驻留在AWS EC2服务器上的ElasticSearch和MongoDB?

javascript - 使用 javascript 选择融合表时出现错误 401

javascript - 使用 Angular 根据表单输入从 MongoDB 中提取数据

javascript - 如何使用 ajax 从文件加载 JSON 对象?