【问题标题】:Node.js chaining promises in a loop with MySQLNode.js 在 MySQL 的循环中链接 Promise
【发布时间】:2018-05-26 14:55:39
【问题描述】:

我正在尝试将非关系数据库转换为关系数据库。所以我从没有唯一 ID 的数据开始。

我需要通过这些行从一个 SQL 调用循环中获取结果,并且对于每一行,使用第一个结果的一部分执行 SQL SELECT,然后使用下一个结果进行另一个 SQL 选择,然后使用来自的 ID 进行写入第一个和最后一个查询。

我正在使用 Node.js,ES6 承诺让一切井井有条,但我似乎遗漏了一些东西。我实际上是在尝试做一个额外的 SQL 调用,并在第三个查询中使用该结果,但我正在简化它,只让一个调用馈入另一个调用。

也许一些代码将有助于显示我正在尝试做的事情。

这是我返回承诺的查询类:

var mysql = require('mysql');

class Database {
    constructor() {
        this.connection = mysql.createConnection({
            host: "localhost",
            user: "root",
            password: "root",
            database: "pressfile"
        }); 
    }

    query(sql, args) {
        return new Promise((resolve, reject) => {
            this.connection.query(sql, args, (err, result, fields) => {
                if (err) return reject(err);

                resolve (result);
            });
        });
    }

    close() {
        return new Promise((resolve, reject) => {
            this.connection.end(err => {
                if (err) return reject (err);

                resolve();
            });
        });
    }
}

这几乎是从教程网站上偷来的,这部分似乎工作得很好。然后是循环和多个查询:

var contactId;
var address1;
var orgName;

var database = new Database();

database.query("SELECT * FROM contact")
    .then( result => {
        for (var i = 0; i < result.length; i++) {
            contactId = result[i].contactId;
            orgName = result[i].org;

            var sql2 = "SELECT * FROM organization WHERE (name = \"" + orgName + "\")";
            console.log(sql2);

            database.query(sql2)
            .then(result2 => {
                console.log(result2);

                var orgId = result2[0].organizationId;
                var sql3 = "INSERT INTO contact_organization (contactId, organizationId) VALUES (" + contactId + ", " + orgId + ")";
                console.log(sql3);

                return ""; //database.query(sql3);
            }).then( result3 => {
                console.log(result3);
            });
        }
    }).catch((err) => {
        console.log(err);
        databse.close();
    });

我知道它在最后有点解开,但我不想做 INSERT 查询,直到我知道我能做对。现在在控制台中,我得到了一个有效的组织对象,然后是:

`INSERT INTO contact_organization (contactId, organizationId) VALUES (17848, 29)'

17848 是在 for 循环中返回的最终 contactId。如何获取在第二个查询之前分配的contactId。我知道我做这些异步的东西不对。

【问题讨论】:

    标签: mysql node.js loops promise


    【解决方案1】:

    试试这样的。只是一个快速的解决方案。 (未测试)。

    const selectOrg = (result) => {
      contactId = result[i].contactId;
      orgName = result[i].org;
      var sql = "SELECT * FROM organization WHERE (name = \"" + orgName + "\")";
    
      return database.query(sql);
    };
    
    const insertOrg = (result) => {
      var orgId = result[0].organizationId;
      var sql = "INSERT INTO contact_organization (contactId, organizationId) VALUES (" + contactId + ", " + orgId + ")";
      return database.query(sql);
    };
    
    database.query("SELECT * FROM contact")
      .then(result => {
        const promises = [];
        for (var i = 0; i < result.length; i++) {
          promises << selectOrg(result)
            .then(insertOrg);
        }
        return Promise.all(promises);
      })
      .then(allResults => {
        console.log(allResults);
      })
      .catch((err) => {
        databse.close();
      });
    

    【讨论】:

    • 我必须清理它一些,例如 result[i] 应该在 for 循环中,而不是在 selectOrg 承诺中。在这一点上,我们所需要的只是“结果”。但是,我仍然让所有组织都链接到同一个contactId 17848,这是循环通过的最后一个contactId。
    • 不过,您的代码还不错。我能够让它运行得很快。但它仍然会产生与上面的原始代码相同的结果。
    • @ScottM 我没有正确阅读您的问题。我不明白How can I get the contactId that is assigned before the second query你能解释一下吗?
    • 在for循环的开始,在'SELECT * FROM contacts'查询返回之后,它分配contactId = result[i].contactId。这是我当时想要的contactId。但是异步代码在开始构建“INSERT INTO contact_organization”...等查询之前会遍历所有这些查询。
    • 我想出了一种将值传递给最终插入查询的技巧,我现在将其写成答案。
    【解决方案2】:

    我找到了一种方法来做到这一点,但它有点俗气。我将 contactId 作为常量包含在 SQL 查询中以获取组织,因此我可以将值传递给 .then,保持一切井井有条。

    我的sql2语句变成:

    var sql2 = "SELECT *, " + contactId + " AS contactId FROM organization WHERE (name = \"" + orgName + "\")";
    

    然后,当该查询返回时,我可以将正确的 contactId 作为 result[0].contactId 提取出来,从我获得 organizationId 的相同结果中提取。

    这是最终代码:

    database.query("SELECT * FROM contact")
        .then( result => {
            for (var i = 0; i < result.length; i++) {
                var contactId = result[i].contactId;
                var orgName = result[i].org;
    
                var sql2 = "SELECT *, " + contactId + " AS contactId FROM organization WHERE (name = \"" + orgName + "\")";
    
                database.query(sql2)
                .then(result2 => {
                    var orgId = result2[0].organizationId;
                    var contactId = result2[0].contactId;
    
                    var sql3 = "INSERT INTO contact_organization (contactId, organizationId) VALUES (" + contactId + ", " + orgId + ")";
                    console.log(sql3);
    
                    return database.query(sql3);
                }).then( result3 => {
                    console.log(result3);
                });
            }
        }).catch((err) => {
            console.log(err);
            databse.close();
        });
    

    console.log(result3) 返回一堆这些:

    OkPacket {
      fieldCount: 0,
      affectedRows: 1,
      insertId: 0,
      serverStatus: 2,
      warningCount: 0,
      message: '',
      protocol41: true,
      changedRows: 0 }
    

    我为从第一个查询返回的每个联系人行插入了一个contact_organization。

    【讨论】:

      猜你喜欢
      • 2018-05-20
      • 2016-06-10
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      • 2016-10-21
      • 2017-07-13
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多