【问题标题】:javascript recursive function with database promises带有数据库承诺的javascript递归函数
【发布时间】:2020-12-04 03:57:41
【问题描述】:

我在这件事上花费了令人尴尬的时间。我可以找到几种可能的解决方案,但我似乎无法将它们映射到我的具体情况。基本问题是我对如何管理承诺缺乏了解。 this 非常接近,可能是我可以使用的解决方案,但我有一个变体,使其无法根据需要直接工作。

我的数据库中有一个用户表。任何用户都可以成为会员,任何会员都可以有 0 到 n 个推荐人。这些推荐中的任何一个也可以推荐成员。给定会员的 member_id,我需要获取他们所有推荐人及其所有推荐人、推荐人......等等的列表,因此这是一个基本的递归问题。挑战是……我似乎无法正确地达成承诺。

通过 api 调用完成的事情:

app.get('/api/calculateReferralTotals', (req, res) => {
    const member_id = req.body.member_id;
    knex.select('member_id').from('users').where({referred_by: 
    member_id}).then((referrals) => {
        GetReferrals(referrals);
        // do something with the global_referral_array but
        // have to deal with the promises first
        res.status(200).send({final_referral_list});
    }).catch((error) => {
        console.log("Error in select " + error);
    });
});

var global_referral_array = [];
function GetReferrals(referrals) {
    referrals.forEach((amb) => {
        knex.select('member_id').from('users').where({referred_by: 
        amb.member_id}).then((ref) => {
            if(ref.length>0) {
            ref.forEach((element) => {
                global_referral_array.push(element.member_id);
            });
                GetReferrals(ref);
            }
        }).catch((error) => {
    });
});

递归函数符合我的预期——我得到了一个引用成员 ID 的列表,但显然我必须以某种方式处理异步性质,这就是我遇到的问题。我以为我可以通过递归构建一组承诺,然后在返回原始调用时解决这些承诺(可能有一个全局承诺数组),但这似乎不起作用。我还尝试将单个 member_id 传递给递归函数并在 DB 调用后继续循环,所以我只处理一次事件,但这也不起作用。

任何指导将不胜感激!

【问题讨论】:

    标签: javascript database recursion promise knex.js


    【解决方案1】:

    这应该可行。

    function GetReferrals(member_id) {
      return knex.select('member_id').from('users').where({referred_by: 
      member_id}).then((referrals) => {
        const referralIds = referrals.map(element => element.member_id)
        return Promise.all(referralIds.map(GetReferrals)).then(referralsReferrals => {
          return referralsReferrals.reduce((final, arr) => final.concat(arr), referralIds)
        })
      })
    }
    
    app.get('/api/calculateReferralTotals', (req, res) => {
        const member_id = req.body.member_id;
        GetReferrals(member_id).then(final_referral_list => {
          // do something with the global_referral_array
          res.status(200).send({final_referral_list})
        }).catch((error) => {
          console.log("Error in select " + error);
        })
    });
    

    【讨论】:

    • 感谢您抽出宝贵的时间...我实际上在选择 TypeError 时遇到错误:refersReferrals.flat is not a function - 我正在使用节点 v10.15.0...我认为 flat 是支持...不是吗?我想知道是否有一种方法可以真正进行一次选择调用...感谢您提供涵盖该案例的可能性!
    • 啊,是的,nodejs v11 及更高版本实际上支持 flat 。我会修改的。关于单个选择调用..如果您使用原始 SQL,这可能是可能的。这个特定端点的预期流量/负载是多少?
    • 还要确保您的 users 表在 referred_by 上有一个索引
    • this question 可能会给您一些关于如何在 SQL 中执行此操作的想法。
    • 哇!那行得通!我真的很感谢你在这里的帮助......我一直被困在这个重要的时间 - 我需要更多地研究这个......我仍然比我现在应该做的更多 - 再次......非常感谢!
    【解决方案2】:

    如果你使用asyc函数会容易得多

    不确定它是否有效,但我会试试这个:

    async function GetReferrals(referrals) {
        if(!referrals) return [] // you need a condition to stop recursion
    
        let promises = referrals.map(amb =>knex.select('member_id').from('users').where({referred_by: 
            amb.member_id}))
    
        let res = await Promise.all(promises)
    
        return [...res, ...res.map(r => await GetReferrals(r)) ]
    });
    

    在主要通话中:

    GetReferrals(referrals).then( result =>
            // do something with the global_referral_array but
            // have to deal with the promises first
            res.status(200).send({final_referral_list});
    )
    

    【讨论】:

    • 谢谢你!我确实忘记将条件放在递归函数中 - 我更新了它......无论如何 - 我会尝试你的方法......一个问题:“结果”实际上会有什么?我输入的评论是一个实际的混淆点 - 我如何处理返回的结果?再次感谢您!
    • result 是一个包含所有referrals.map(amb =>knex.select('member_id').from('users').where({referred_by: amb.member_id})) 结果的数组如果你尝试它,请告诉我它是否有效,谢谢!!
    猜你喜欢
    • 2015-12-05
    • 2017-12-18
    • 2017-05-09
    • 2018-12-01
    • 2018-10-11
    • 2019-05-25
    • 2017-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多