You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 14:57:03