【问题标题】:Fetch multiple documents in a stored procedure (Azure DocumentDB)在存储过程中获取多个文档 (Azure DocumentDB)
【发布时间】:2017-02-17 03:59:08
【问题描述】:

我有两种文档类型,列表和产品。列表对象包含某些国家/地区的产品列表,如下所示:

列表

{
  "Name": "Default",
  "Countries": {
    "_default": [
      "4QlxAPFcCAAPAAAAAAAAAA==",
      "4QlxAPFcCAAHAAAAAAAAAA=="
    ],
    "US": [
      "4QlxAPFcCAAIAAAAAAAAAA==",
      "4QlxAPFcCAAHAAAAAAAAAA=="
    ]
  },
  "Type": "Listing",
  "id": "dfed1839-07c5-482b-81c5-669b1dbcd0b6",
  "_rid": "4QlxAPFcCAAEAAAAAAAAAA=="
}

产品:

{
    "Name": "Widget",
    "Price": 3.45,
    "Type": "Product",
    "_rid": "4QlxAPFcCAAHAAAAAAAAAA=="
}

我的目标是在 Azure DocumentDB 集合中创建一个存储过程,该集合采用两个参数 ridcountry,这实际上将获取列表文档和该国家/地区的文档,以最有效的方式。我的假设是使用 getContext().getCollection().readDocument(...) 通过其资源 ID 加载 Document 是最快的方式,因此尝试为此创建一个存储过程。

我的尝试是嵌套连续调用(回调地狱?),使用带有 yield 的生成器/迭代器,然后使用纯 Promise 方法。所有的尝试都给出了相同的结果:

它将获取第一个文档,但在收到文档后会突然结束。

作为参考,这是我最近的尝试:

function test(rid, country) {
    var collection = getContext().getCollection();
    var collectionSelfLink = collection.getSelfLink();
    var docsLink = collectionSelfLink + "docs/";
    var body = getContext().getResponse().setBody;  

    function getDocument(rid) {
        return new Promise(function(resolve, reject) {
            var accepted = collection.readDocument(docsLink + rid, (err, doc, opts) => {
                resolve(doc);
            });

            if (!accepted)
                reject("Not accepted");            
        });
    }

    getDocument(rid)
        .then(doc => { 
            body("0. First step"); // set test body 

            // Countries is a Dictionary<string, string[]> with resource ids
            return doc.Countries[country] || doc.Countries["_default"];
        })
        // This is how far it gets, resulting in response "1. Documents to fetch: 2"
        .then(a => body("1. Documents to fetch: " + a.length))
        .then(a => a.map(function(productId) { return getDoument(productId); }))
        .then(a => body("2. It should come this far, right?"))
        .then(a => Promise.all(a))
        .then(a => body(a))
        .catch(function(e) { throw new Error(JSON.stringify(e)); });
}

【问题讨论】:

  • 我不是承诺专家。我倾向于手动编写回调代码或使用 async.js(是的,您可以将其作为 sproc 中的依赖项加载),但我想知道您的问题是否在调用 a.map 的行中。包装.then 将返回一个promise,它是从那时起的promise 数组。此外,您在 .then() 调用中偏爱单行函数,但其​​中一些事情(对 body 的调用甚至对 .map 的调用可以在线完成。您真正需要承诺的唯一事情是异步调用阅读文档。另一方面,这可能只是一种承诺编码风格。
  • 我在 REPL 中使用模拟的getDocument 函数尝试了上述调用链,它可以工作。如前所述,我还尝试在初始 collection.readDocument(...) 内执行 for 循环,当使用 for-of/for-in/for 时,它将中途终止(从我在列表)。当使用.forEach 时,它会遍历整个数组,但不会等到调用完成。我很好奇调用者如何确定何时“终止”......
  • 阵列有多大?扇出 (a.map()) 承诺链如何决定要实现多少并行化?我的新理论是,使用 for 循环或您的 a.map 承诺方法,您的扇形太宽并超出了某些资源。您可能需要像 async.js 的 ...Limit() 方法那样限制并行化。
  • 这里已经有几天没有答案了。目前情况如何?
  • 我已经发布了对我的问题的建议答案,因为 Promise 根本不起作用。 @LarryMaccherone,获取的文档数量仅在 2 到 4 个之间,因此并行度并不高。

标签: node.js azure azure-cosmosdb


【解决方案1】:

事实证明,嵌套调用 do 实际上有效,如果您经常更改响应正文(?)

以下过程按预期工作:

function test(rid, country) {
    var collection = getContext().getCollection();
    var collectionSelfLink = collection.getSelfLink();
    var docsLink = collectionSelfLink + "docs/";
    var body = getContext().getResponse().setBody;

    var accepted = collection.readDocument(docsLink + rid, (err, doc, opts) => {
        if (err) throw new Error(err.message);

        // Countries is a Dictionary<string, string[]> with resource ids
        var offerIds = doc.Countries[country] || doc.Countries["_default"];
        var result = [];

        for (var docId of offerIds) {
            var subAccepted =
                collection.readDocument(docsLink + docId, (err, doc, opts) => {
                    if (err) throw new Error(err.message);

                    result.push(doc);
                });

            if (!subAccepted)
                throw new Error("A subsequent request was not accepted");

            body(result); // <-- Note, setting body in each iteration.
        }
    });

    if (!accepted)
        throw new Error("The request was not accepted");
}

【讨论】:

  • 应该指出,这并没有我预期的那么好。从客户端进行类似查询甚至更快
猜你喜欢
  • 2017-09-23
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-16
相关资源
最近更新 更多