Javascript 在递归节点函数中从Mongoose检索树数据

Javascript 在递归节点函数中从Mongoose检索树数据,javascript,node.js,mongodb,express,tree,Javascript,Node.js,Mongodb,Express,Tree,我试图在Node Express应用程序中使用Mongoose递归地从Mongodb检索树格式的数据。我试图用承诺来做这件事,但我显然做得不对 假设您拥有mongodb表foos”: { "_id": { "$oid": "5b5fb27232db7b13a1090577" }, "bazs": [ { "$oid": "5b626a2e325c181bdf4fba08" } ], "

我试图在Node Express应用程序中使用Mongoose递归地从Mongodb检索树格式的数据。我试图用承诺来做这件事,但我显然做得不对

假设您拥有mongodb表
foos
”:

{
    "_id": {
        "$oid": "5b5fb27232db7b13a1090577"
    },
    "bazs": [
        {
            "$oid": "5b626a2e325c181bdf4fba08"
        }
    ],
    "bars": [
        {
            "$oid": "5b5fb3cc32db7b13a1090579"
        }
    ],
    "name": "Parent1",
    "accountId": "5b5fb27132db7b13a1090576",
    "__v": 0
}
这有两种不同的子对象。此外,
baz
对象还有其他
baz
对象作为子对象,以及
bar
对象。假设这是
条的id所对应的表:

{
    "_id": {
        "$oid": "5b626a2e325c181bdf4fba08"
    },
    "bazs": [
        {
            "$oid": "5b5fb3cc32db7b75fa01"
        }
    ],
    "bars": [
        {
            "$oid": "5b5fb3c7cdaf740a500a"
        }
    ],
    "accountId": "5b5fb27132db7b13a1090576",
    "parent": {
        "$oid": "5b5fb27232db7b13a1090577"
    },
    "__v": 0
}
我一直在使用递归函数,等待使用Mongoose检索对象类型

const getObjectRecursive = (type, id)=>{     //'type' will be 'Foo' or 'Bar'
    return new Promise((resolve, reject)=>{
        type.findOne.call(type, {_id:id},{}, err=>{
            if(err){
                reject(err);
            }
        })
            .then((rslt)=>{
                const result = rslt;
                const bars = result.bars;
                const bazs = result.bazs;
                result.children = {};
                result.children.bars = tasks.map(async barId=>{
                    const barIdString = barId.toString();
                    await getBarRecursive(barIdString, err=>{
                        if(err){
                            reject(err);
                        }
                    });
                });
                result.children.bazs = bazs.map(async eventId=>{
                    const bazIdString = bazId.toString();
                    await Baz.findOne({_id:eventIdString}, {},err=>{
                        if(err){
                            reject(err);
                        }
                    });
                });
                resolve(result);
            })
    });

}
我在这两个函数中使用它:

const getBarRecursive = (taskId)=>{
    return getObjectRecursive(Bar, taskId);

}

const getFooRecursive=(categoryId)=>{
    return getObjectRecursive(Foo,categoryId);
};
这条路线称之为:

router.get('/:id', verifyToken, (req,res)=>{
    Branch.getFooRecursive(req.params.id)
        .then(
            (foo)=>{
                res.status(200).send(cat);
            },
            (err)=>{
                res.status(500).send(err);
            }
        )
});
这意味着递归返回树对象和所有对象的子对象。发生的情况是,子对象
result.children.bar
result.children.baz
变成了永远无法兑现的承诺

我知道,这不是最好的办法。很明显,我没有做出正确的承诺。我还考虑过使用$graphLookup检索表,但我不知道如何检索,因为子项来自不同的集合

我如何让应用程序检索到任何深度的孩子

更新:这仍然不起作用。我已将递归函数更改为:

const getObjectRecursive = async (type, id)=>{     
    const rslt = await type.findOne.call(type, {_id:id},{}, {}, err=>{
        if(err){
            return({err: err});
        }
    });

    const result = rslt.toObject();
    const bars = result.bars;
    const bazs = result.bazs;
    result.children = {};
    result.children.bars = tasks.map(async barId=>{
        const barIdString = barId.toString();
        await getBarRecursive(barIdString, err=>{
            if(err){
                reject(err);
            }
        });
    });
    result.children.bazs = bazs.map(async eventId=>{
        const bazIdString = bazId.toString();
        await Baz.findOne({_id:eventIdString}, {},err=>{
            if(err){
                reject(err);
            }
        });
    });
    return result
};
其他一切都一样。现在发生的事情是,包含
结果的承诺直到结果发送到客户端后才得以实现,因此我在它的位置上得到了一个空对象,如下所示:

{
    "bars": [
        "5b626a2e325c181bdf4fba08"
    ],
    "bazs": [],
    "_id": "5b5fb27232db7b13a1090577",
    "__v": 0,
    "children": {
        "bars": [
            {}
        ],
        "bazs": []
    }
}
我尝试过的一些事情:

  • bar.map(async barId=>…
    等)放置在Promises.all语句中,并将其分配给
    语句中的
    result.children
    。然后(…)
    语句
  • bar.map(async barId=>…
    等)放在一个单独的异步函数中,然后说
    result.children.bar=wait getAllTasks(tasks)

如何确保在发送结果之前履行承诺?

Mongoose支持承诺很长时间,不需要使用回调。
拒绝
函数未定义,其使用将导致异常。此外,
调用
在这里是不合理的。还有一些不一致,
任务
vs
 条形图
eventId
vs
bazId
。所有这些都会阻止代码正常工作

应该是这样的:

const getObjectRecursive = async (type, id)=>{     
    const result = await type.findOne({_id:id}).lean();
    const barsPromises = result.bars.map(barId=>{
        return getBarRecursive(barId.toString()); // shouldn't it accept 2 args?
    });
    const bazsPromises = result.bazs.map(bazId =>{
        return Baz.findOne({_id:bazId.toString()}).lean();
    });

    const [bars, bazs] = await Promise.all([
      Promise.all(barsPromises),
      Promise.all(bazsPromises)
    ]);
    result.children = { bars, bazs };

    return result;
};

该示例大量使用.Mongoose支持承诺。为什么一直使用findOne回调?您将这些东西与async/await混合使用。如果您在任何地方都使用async/await,问题可能会得到解决。因此,您的意思是,与其让findObjectRecursive返回承诺,不如将其与getFooRecursive和getBarRecursive转换为async函数?如果需要,您仍然可以使用递归,但更干净的控制流会为错误留下更少的空间。
const result=await type.findOne(…)
,等等。我明天会试试这个wbtw,默认情况下这样做是个好主意,除非您需要相反的方法。这样做就像
const result=await type.findOne(…).lean()