CosmosDB存储过程递归查询嵌套数据无需response.setBody()返回方案咨询
解答
问题1:如何将MyRecursiveFunction获取的数据返回给上层调用的父函数
你现在遇到的返回值无效问题,核心原因是CosmosDB存储过程中的collection.queryDocuments是异步API,回调函数里的return只会把值返回给回调的触发逻辑,根本无法传递到外层MyRecursiveFunction的调用栈。
你可以通过回调传值+异步计数的方式实现层级数据组装:在顶层定义最终要返回的层级结构对象,给递归函数增加回调参数,每次查询到子文档后直接挂载到对应父节点的属性上,同时用计数器统计所有异步查询的完成状态,等全部查询执行完毕后再统一调用response.setBody()返回完整结构。
参考修改后的代码:
function GetGroups(Id) { var context = getContext(); var collection = context.getCollection(); var response = context.getResponse(); // 顶层结果存储 var finalResult = []; // 异步操作计数器,避免提前返回 var pendingQueries = 0; var query = "MY QUERY"; var accepted = collection.queryDocuments(collection.getSelfLink(), query, function (err, documents, responseOptions) { if (err) throw new Error("Error" + err.message); if (documents.length === 0) throw "Unable to find document"; // 初始化待处理查询数 pendingQueries = documents.length; for (let i = 0; i < documents.length; i++) { // 把父文档先加入结果集,再递归挂载子节点 finalResult.push(documents[i]); MyRecursiveFunction(documents[i], function() { // 每完成一个父节点的递归,计数器减1 pendingQueries--; // 所有查询都完成时返回最终结果 if (pendingQueries === 0) { response.setBody(finalResult); } }); } } ) if (!accepted) throw "Some error happened"; function MyRecursiveFunction(parentDoc, doneCallback) { // 无子节点直接完成 if (!parentDoc.children || parentDoc.children.length === 0) { return doneCallback(); } // 统计当前父节点的子查询数 let childPending = parentDoc.children.length; // 给父节点加fullChildren属性存完整子文档 parentDoc.fullChildren = []; for (let i = 0; i < parentDoc.children.length; i++) { let query = "MY QUERY TO GET DOCUMENT BY ID"; var accepted = collection.queryDocuments(collection.getSelfLink(), query, function (err, child, responseOptions) { if (err) throw new Error("Error" + err.message); if (child.length === 0) throw "Unable to find documents"; // 把子文档挂到父节点上 parentDoc.fullChildren.push(child[0]); // 递归处理子文档的子节点 MyRecursiveFunction(child[0], function() { childPending--; // 当前父节点的所有子节点都处理完,触发回调 if (childPending === 0) { doneCallback(); } }); } ) if (!accepted) throw "Some error happened"; } } }
问题2:两次独立查询是否会限制续传令牌的使用
不会限制。续传令牌是和单个查询绑定的,父文档查询和子文档查询的续传令牌完全独立,互不干扰:
- 如果父文档查询结果超过单次返回上限,你可以在父查询的回调里拿到
responseOptions.continuation存下来,等当前批次的父文档+子文档全部处理完成后,再用这个续传令牌查询下一批父文档即可。 - 子文档查询如果需要用到续传,同理可以单独处理每个子查询的续传逻辑。
需要注意:CosmosDB存储过程的单次执行最大时长为5秒,如果你的数据量极大需要多次续传才能处理完,建议把当前处理到的续传令牌随部分结果返回给客户端,由客户端发起下一次存储过程调用继续处理,避免超时。
内容的提问来源于stack exchange,提问作者Jeppe Christensen
相关产品推荐
相关产品推荐

