0

我基本上需要进行大约 3 次调用来获取 json 对象的数据。它基本上是 JSON 对象的 JSON 数组,具有一些属性,其中一个是使用第二个查询选择的其他值的数组,然后那个也有使用另一个数据库调用选择其中的数组。

我尝试使用 asyn.concatSeries 以便我可以深入了解底部调用并将我为一个根 json 对象收集的所有信息放在一起,但这会产生很多意想不到的行为..

JSON 示例

[
    {
       "item" : "firstDbCall"
       "children" : [ {
                       "name" : "itemDiscoveredWithSecondDBCall"
                       "children" : [ itemsDiscoveredwith3rdDBCall]
                      },
                    ]
    }
]

使用 node.js 真的很难。我真的需要弄清楚如何正确地做到这一点,因为我必须为不同的目的做很多这些。

编辑 这是我的代码。async.concatSeries 有一些奇怪的行为。在每个数组的每个函数完成后,结果会被多次调用。所以我不得不检查一下。我知道这是非常混乱的代码,但在过去的 2 个小时里,我只是在上面贴了创可贴以使其正常工作..

console.log("GET USERS HAREDQARE INFO _--__--_-_-_-_-_____");
var query = "select driveGroupId from tasks, driveInformation where agentId = '" 
        + req.params.agentId + "' and driveInformation.taskId = tasks.id order by driveInformation.taskId desc;";

connection.query(query, function(err, rows) {
    if (rows === undefined) {
        res.json([]);
        return;
    } 
    if(rows.length<1) { res.send("[]"); return;}
    var driveGroupId = rows[0].driveGroupId;
    var physicalQuery = "select * from drives where driveGroupId = " + driveGroupId + ";";
    connection.query(physicalQuery, function(err, rows) {
        console.log("ROWSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS");
        console.log(rows);
        async.concatSeries(rows, function(row, cb) {
            console.log("-------------------------------SINGLE ROW-------------------------------------");
            console.log(row);
            if(row.hasLogicalDrives != 0) {
                console.log("HAS LOGICAL DRIVES");
                console.log(row.id); 
                var query = "select id, name from logicalDrives where driveId = " + row.id;
                connection.query(query, function(error, drives) {
                    console.log("QUERY RETURNED");
                    console.log(drives);
                    parseDriveInfo(row.name, row.searchable, drives, cb);

                });
            }
            else
                var driveInfo = { "driveName" : row.name, "searchable" : row.searchable};
                console.log("NO SUB ITEMS");
                cb(null, driveInfo);
        }, function(err, results) {
            console.log("GEETTTTINGHERE");
            console.log(results);
            if(results.length == rows.length) {
                console.log("RESULTS FOR THE DRIVE SEARCH");
                console.log(results);
                var response = {"id": req.params.agentId};
                response.driveList = results;
                console.log("RESPONSE");
                console.log(response);
                res.json(response);
            }
        });
    });
});     

 };

 parseDriveInfo = function(driveName, searchable, drives, cb) {
async.concatSeries(drives, function(drive,callback) {
    console.log("SERIES 2");
    console.log(drive);
    console.log("END OF DRIVE INFO");
    var query = "select name from supportedSearchTypes where logicalDriveId = " + drive.id;
    connection.query(query, function(error, searchTypes) {
        drive.searchTypes = searchTypes;
        var driveInfo = { "driveName" :driveName,
            "searchable" : searchable,
            "logicalDrives" : drive
        };

        callback(null, driveInfo);

    });
}, function (err, results) {
    console.log("THIS IS ISISIS ISISISSISISISISISISISISISIS");
    console.log(results);
    if(results.length === drives.length) {
        console.log("GOTHERE");
        cb(null, results);
    }
});     

}

4

3 回答 3

1

使用 async 获得足够好,在正确的情况下使用正确的方法组合需要相当多的经验。async.waterfall如果它的 query1 然后 query2(dataFoundByQuery1) 然后 query3(dataFoundByQuery2) 则很可能可以处理您的案例。但根据具体情况,您需要适当地混合和匹配异步方法,有时有 2 个级别 - 例如“大图” async.waterfall,其中瀑布中的某些步骤async.parallelasync.series根据需要执行。我从来没有使用过async.concat并考虑到您的需求,我认为您选择了错误的方法。主力是async.each, async.eachSeries, async.waterfall, 和async.map,至少对于我最常遇到的网络应用程序和数据库查询用例而言,因此在探索更具体的便捷方法之前,请确保您确实了解了这些用例。

于 2013-06-21T19:18:57.550 回答
0

我强烈建议使用sequelize.js它提供了一个非常强大的 orm 允许您将查询链接在一起。它还允许您直接将数据加载到 js 对象中,编写动态 sql,并连接到许多不同的数据库。图片来自 Ruby 世界的 Node.js 的 ActiveRecord。

于 2013-06-21T21:21:57.263 回答
0

编辑:这是一个更深入的示例,基于您似乎正在使用的连接库的使用。请注意,其中一些是 javascript 伪代码。向 resultsArray 添加对象之类的事情显然还没有完成,我唯一花时间确保正确的是与回调有关的“逻辑流”。其他一切都由您来实施。为了支持对同一个回调函数的多次调用并保持每次调用的状态,最好的方法是将一组回调包装在一个闭包中。这允许回调与主事件循环共享一些状态。这允许您将参数传递给回调,而实际上不必将它们作为参数传递,就像 c++ 中的类变量,甚至 javascript 中的全局变量一样,但我们没有污染全局范围:)

function queryDataBase(query) {
//wrap the whole query in a function so the callbacks can share some
//variables with similar scope.  This is called a closure

    int rowCounter = 0;
    var dataRowsFromStep2;
    var resultsArray = {};

    connection.query(query, dataBaseQueryStep2);

    function dataBaseQueryStep2(err, rows) {
        //do something with err and rows
        dataRowsFromStep2 = rows;

        var query = getQueryFromRow(dataRowsFromStep2[rowCounter++]);//Always zero the first time.  Might need to double check rows isn't empty!

        connection.query(query, dataBaseQueryStep3);
    }

    function dataBaseQueryStep3(err, rows) {
        //do something with err and rows

        if(rowCounter < dataRowsFromStep2.size) {
            resultsArray.add(rows);//Probably needs to be more interesting, but you get the idea
            //since this is within the same closure, rowCounter maintains it's state
            var query = getQueryFromRow(dataRowsFromStep2[rowCounter++]);

            //recursive call query using dataBaseQueryStep3 as it's callback repeatedly until
            //we run out of rows to call it on.
            connection.query(query, dataBaseQueryStep3)
        } else {
            //when the if statement fails we have no more rows to run queries on so return to main program flow
            returnToMainProgramLogic(resultsArray);
        }

    }
}

function returnToMainProgramLogic(results) {
    //continue running your program here
}

我个人比 async 产生的语法更喜欢上面的逻辑......我相信你的问题的核心在于你对 async 的嵌套调用,以及 ASYN 本身异步运行一系列函数的事实,但是按顺序(混淆我知道)。如果你这样写你的程序,你就不用担心了!

于 2013-06-21T18:51:33.523 回答