在递归节点函数中从猫鼬检索树数据

时间:2018-08-03 23:50:11

标签: javascript node.js mongodb express tree

我正在尝试使用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.barsresult.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)

在发送结果之前,如何确保我的诺言得到履行?

1 个答案:

答案 0 :(得分:0)

猫鼬很长一段时间都支持诺言,不需要使用回调。 reject函数未定义,其使用将导致异常。另外,call在这里是不合理的。 tasksbarseventIdbazId之间也存在一些不一致之处。所有这些都会阻止代码正常工作

应该是这样的:

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;
};