多个异步mongo请求生成混乱的返回

时间:2013-10-16 13:29:45

标签: json node.js mongodb asynchronous async.js

我正在尝试在我的mongodb上的多个请求中构建一个JSON。 因为我没有使用DBRef,所以我必须自己构建“桌面接头”,这就是我在这个混乱中的结果。 这段代码给我带来了几天的麻烦。 (mongo部分用mongoskin完成)

        var getUserFeed = function(thelimit, out) {
          userfeed = db.collection("userfeed");
          apparel = db.collection("apparel");
          store = db.collection("stores");
          if(thelimit)
            args = {limit:thelimit, sort: [['date',-1]]};

          userfeed.find({},args).toArray(function(e, feed) {
            if (e) console.log("error: ", e);
            // gather aparel infos
            var i=0;
            var ret_feeds = [];
            feed.forEach(function(cur_feed) {
                var outfits=[];
                console.log("beginning with: " + cur_feed.url);
                var resfeed = "";
                resfeed = cur_feed;
                resfeed.url = baseurl + snapurl + resfeed.url + "_small.jpg";
                i=0;
                cur_feed.apparel_ids.forEach(function(item) {
            /*>>*/  apparel.find({"_id": item},{limit:1}).toArray(function(e, results) {
                        console.log(">>>>>>>>>>> APPAREL_FIND { i:" + i + "}");
                        if (e) console.log("error: ", e);
                        results = results[0];
                        if(results.apparel_cat == 1)
                            url_subcat = "pants/";
                        else if(results.apparel_cat == 2)
                            url_subcat = "shirts/";
                        else if(results.apparel_cat == 2)
                            url_subcat = "tshirts/";

                        results.thumb = baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg";
                        results.size = "M"; ///// TOBE REAL VERY SOON
                        results.gallery = [
                            baseurl + outfiturl + url_subcat + results.apparel_id + "/model.jpg",
                            baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg"
                        ];
                        outfits.push(results); // quick and dirty, 2 b refined..
                        i++;
                        if(i>=cur_feed.apparel_ids.length)
                        {
                            // pack it up
        //                  resfeed.url = resfeed.url;
                            resfeed.outfits = outfits;
                            resfeed.fav = false;
                            resfeed.bough = false;

                            // retrieve store infos
                /*>>>*/     store.find({"_id":resfeed.store_id}, {limit: 1}).toArray(function(e, resstore) {
                                console.log("\t############# STORE_FIND { i:" + i + "}");
                                if (e) console.log("error: ", e);
                                resfeed.store = resstore[0];
                                resfeed.store.class = "hem";
                                ret_feeds.push(resfeed);
                                if(ret_feeds.length >= feed.length)
                                {
                                    console.log("\t\t@@@@@@@@@@@@@@@@@@@@@@calling return [ ret_feeds.length = " + ret_feeds.length + " feed.length = " + feed.length);
                                    out.send(ret_feeds);
                                }
                            });
                        }
                  });
                });
            });
          });
        }

此代码失败,因为在完成任务之前返回json,所以下次尝试返回另一个json时,由于标题已经被发送,它会崩溃。

现在你可以看到,我有3个收藏:userfeed,apparel和store。 此函数的目标是检索userfeed集合中的所有项目,提取服装(基于作为userfeed集合的一部分的outfit_id数组),并以相同的方式提取与每个userfeed条目相关的商店信息,像这样:

enter image description here

我知道async.js或者同等的东西是要走的路:我在这里像其他很多帖子一样红,但是我仍然无法理解它,可能是因为它背后的整个机制async.js或流控制一般来说它仍然是我脑海中的焦点。 我仍然是节点上的菜鸟:)

更新

我认为我在这里找到了正确的理解路径:http://www.sebastianseilund.com/nodejs-async-in-practice

这个人通过用例描述用例的所有方法在将async.js应用到代码方面做得非常出色。 我会在解决问题后立即发布解决方案。

更新2

感谢上面的老兄,我可以找到一个有效的解决方案,下面就是答案。

1 个答案:

答案 0 :(得分:0)

经过这么多努力,我终于找到了解决方案。 async.js是答案,因为我(显然)怀疑。

仅供参考,这是工作代码。 如果您想指出改进或其他任何内容,那么非常欢迎

var getUserFeed = function(thelimit, out) {
userfeed = db.collection("userfeed");
apparel = db.collection("apparel");
store = db.collection("stores");
var args;
if(thelimit)
    args = {limit:thelimit, sort: [['date',-1]]};

var outfits=[];
var feeds = array();

async.series([
    // userfeed find
    function(callback) {
        userfeed.find({},args).toArray(function(e, feed) {
            if(e) callback(e);
            feeds = array(feed);
            console.log(feeds.length + " retrieved. stepping in");
            callback(null, null);
        });
    },

    // join
    function(callback) {
        async.forEach(feeds, function(thefeed, callback) {
            var i = feeds.indexOf(thefeed);
            async.parallel([
                // load apparel infos
                function(callback) {
                    console.log("\t >>> analyzing thefeed id " + thefeed._id);
                    async.forEach(thefeed.apparel_ids, function(apparel_id, callback) {
                        apparel.find({"_id": apparel_id},{limit:1}).toArray(function(e, results) {
                            if (e) console.log("error: ", e);
                            results = results[0];
                            if(results.apparel_cat == 1)
                                url_subcat = "pants/";
                            else if(results.apparel_cat == 2)
                                url_subcat = "shirts/";
                            else if(results.apparel_cat == 2)
                                url_subcat = "tshirts/";

                            results.thumb = baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg";
                            results.size = "M"; ///// TOBE REAL VERY SOON
                            results.gallery = [
                                baseurl + outfiturl + url_subcat + results.apparel_id + "/model.jpg",
                                baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg"
                            ];
                            console.log("\t\t### pushing data into thefeed_index: " + i);
                            if(!util.isArray(feeds[i].oufits)) feeds[i].outfits = array();
                            feeds[i].outfits.push(results);
                            callback(null, null);
                        });
                    }, callback);
                },
                // load store infos
                function(callback) {
                    store.find({"_id":thefeed.store_id}, {limit: 1}).toArray(function(e, resstore) {
                        console.log("\t### STORE_FIND");
                        if (e) console.log("error: ", e);
                        feeds[i].store = resstore[0];
                        feeds[i].store.class = "hem";
                        callback(null, null);
                    });
                }
            ], callback);
        }, callback);
    }

    // MAIN
    ], function(err, result) {
        console.log("feed retrieval completed. stepping out");
        if (err) return next(err);
        out.send(feeds);
    });
};