我正在尝试使用Node Express应用程序中的Mongoose从Mongodb递归地以树格式检索数据。我正在努力兑现承诺,而我显然做错了。
假设您有mongodb表foos
':
{
"_id": {
"$oid": "5b5fb27232db7b13a1090577"
},
"bazs": [
{
"$oid": "5b626a2e325c181bdf4fba08"
}
],
"bars": [
{
"$oid": "5b5fb3cc32db7b13a1090579"
}
],
"name": "Parent1",
"accountId": "5b5fb27132db7b13a1090576",
"__v": 0
}
因此,它具有两种不同类型的子对象。同样,baz
对象还有其他baz
对象作为子对象,还有bar
对象。假设这是bars
的ID表:
{
"_id": {
"$oid": "5b626a2e325c181bdf4fba08"
},
"bazs": [
{
"$oid": "5b5fb3cc32db7b75fa01"
}
],
"bars": [
{
"$oid": "5b5fb3c7cdaf740a500a"
}
],
"accountId": "5b5fb27132db7b13a1090576",
"parent": {
"$oid": "5b5fb27232db7b13a1090577"
},
"__v": 0
}
我一直在使用thunk的递归函数,以等待使用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.bars
和result.children.bazs
变成了无法实现的承诺。
我知道,这不是最好的方法。我显然没有正确履行诺言。我还考虑过使用$ 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
};
其他所有内容都相同。现在正在发生的事情是,直到将结果发送给客户端之后,包含bar
结果的承诺才会被兑现,所以我得到的是一个空对象,就像这样:
{
"bars": [
"5b626a2e325c181bdf4fba08"
],
"bazs": [],
"_id": "5b5fb27232db7b13a1090577",
"__v": 0,
"children": {
"bars": [
{}
],
"bazs": []
}
}
我尝试过的一些事情:
bars.map(async barId=>...
等放在Promises.all语句中,然后在result.children
语句中将其分配给.then(...)
bars.map(async barId=>...
等放在单独的异步函数中,然后说出result.children.bars = await getAllTasks(tasks)
在发送结果之前,如何确保我的诺言得到履行?
答案 0 :(得分:0)
猫鼬很长一段时间都支持诺言,不需要使用回调。 reject
函数未定义,其使用将导致异常。另外,call
在这里是不合理的。 tasks
与bars
和eventId
与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;
};