如何用JavaScript编写递归异步搜索实现MongoDB对象树查找
代码问题排查
原有代码存在几个核心逻辑缺陷,导致无法实现树状搜索效果:
- 关联ID提取错误:
return object.value.main, object.value.included受逗号运算符影响,只会返回included字段的值,丢失main字段的关联ID - 缺少深度终止判断:未对
depth <= 0的情况做处理,深度耗尽后仍会继续递归,容易触发栈溢出或无效查询 - 分支污染:
previousList为引用传递,不同搜索分支的已访问ID会互相覆盖,导致部分路径被误判为已访问 - 结果返回逻辑错误:
then回调内的return只会终止回调本身,无法终止外层for循环和函数,找到匹配路径后不能及时返回 - 异常分支无返回值:无匹配路径时函数无显式返回,路径拼接时会出现
undefined等异常值
调整后实现树状搜索的代码
async function objectFinder(ID1, ID2, depth, previousList = []) { // 命中目标直接返回路径 if (ID1 === ID2) { return [ID2] } // 深度耗尽或深度非法直接返回空 if (depth <= 0) { return null } // 每个分支独立维护已访问列表,避免分支污染 const currentVisited = [...previousList, ID1] // 拉取当前节点对象 const obj1 = await findObjectByID(ID1) // 合并所有关联ID const connectedID = obj1.connections.concat(obj1.inclusions) // 批量查询关联ID的关联关系 const mapPromises = connectedID.map(id => findID(id)) const fulfilled = await Promise.allSettled(mapPromises) // 提取所有有效关联ID,过滤已访问的 const relatedIds = fulfilled .filter(item => item.status === 'fulfilled') // 过滤查询失败的请求 .flatMap(item => [item.value.main, item.value.included]) // 同时提取main和included的ID .filter(id => id && !currentVisited.includes(id)) // 过滤空值和已访问的ID // 遍历子节点递归搜索 for (const id of relatedIds) { const result = await objectFinder(id, ID2, depth - 1, currentVisited) // 找到匹配路径直接拼接返回 if (result) { return [ID1, ...result] } } // 当前分支无匹配路径返回空 return null }
功能说明
- 本实现为深度优先的树状搜索,每个ID对应搜索树的一个节点,节点的子节点为该ID对应对象的所有关联ID
- 每个搜索分支独立维护已访问ID列表,避免循环引用导致的无限递归,也不会出现分支间的污染问题
- 支持通过
depth参数控制搜索树的最大深度,避免无意义的深层查询 - 找到目标ID后会直接返回完整的ID路径,无匹配路径时返回
null,方便上层逻辑判断
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

