Azure上的DocumentDb - 我无法在一次运行中获得完整的记录集?

时间:2016-04-10 13:25:03

标签: azure azure-cosmosdb

对于一个应用程序,我创建了一个在AzureDB上运行的javascript存储过程,这样我就可以获得一组全面的求和,然后我可以在屏幕上显示。

然而,计数总是关闭,似乎我从未获得完整的记录集。

所以我做了一个测试。我创建了以下存储过程:

function trialRun(startDateTime, endDateTime)
{
    var context = getContext();
    var collection = context.getCollection();
    var response = context.getResponse();

    var sqlString = "select p.id, p.ClientId, p.ActionType, a.Action, a.TimeStamp "
                  + "from History p"
                  + "     join a in p.Actions "
                  + "where a.TimeStamp >= '" + startDateTime + "' "
                  + "  and a.TimeStamp <= '" + endDateTime + "' ";

    // Query documents
    var isAccepted = collection.queryDocuments(collection.getSelfLink(), sqlString,
                                               function (err, feed, options)
                                               {
                                                    if (!err)
                                                    {
                                                        response.setBody(JSON.stringify(feed));
                                                    }
                                                    else
                                                    {
                                                        throw err;
                                                    }
                                               });

    if (!isAccepted) { throw new Error("The query was not accepted by the server."); }
}

事实上,输出错过了10条记录。

我读过有关分页的内容......但到目前为止我还没有找到与此问题有关的任何内容。

这里有谁可以让我朝着正确的方向前进?也许是关于如何从下一个&#34;页面获取数据的示例代码?

2 个答案:

答案 0 :(得分:1)

首先推荐。如果你所做的只是一个查询,你最好使用客户端SDK和/或documentdb-utils(这只是Azure提供的SDK的包装器)。 sproc内部的查询不会使用辅助节点并限制整体吞吐量。来自客户端SDK的查询将使用辅助节点,并且性能更高。另一方面,如果你将一堆行聚合到一个结果,那么sproc可能是最好的,具体取决于。

也就是说,即使你将聚合移动到sproc中,你也会遇到同样的问题。因此,要解决这个问题,您可能需要查看documentdb-utils中的一个示例。从countDocuments sproc开始。此外,您可能希望了解用于编写here找到的可重新启动的sprocs的模式。

我怀疑你缺少的关键概念是在NoSQL世界中,特别是在JavaScript中,你需要异步思考并编写代码,以便可以中断和重新启动它。

假设您可以将聚合需求转移到sproc中,那么您所需的更改包括:

  1. 系统停止接受请求时不要抛出错误。而是保存当前的执行状态,并包含一个指示符,需要重新启动sproc。我链接到的countDocuments示例使用stillQueueing。如果你使用documentdb-utils,那将告诉它sproc没有完成,需要再次调用。

  2. queryDocuments() requestOptions的{​​{1}}来电中添加第三个参数,并将pageSize设置为1000. 1000足够大,您将无法获得大量的回合跳转到数据库,但足够小,你可以在系统返回false之后处理它,表明它不再排队请求但是在强制超时之前。

  3. 当页面进入您的聚合时,会将结果累积到您将返回的正文中。

  4. 您无需JSON.stringify()回复。他们的系统将负责编组纯JavaScript对象。

  5. 在任何情况下,都不要将整个Feed添加到您的回复中。只有你的聚合。

  6. 捕获在回调的第三个options参数中找到的延续令牌,并将其与您的回复一起传回。

  7. 如果你真的想使用一个sproc并返回所有行而不是客户端SDK或只有聚合的sproc,那么我需要警告你不要使用documentdb-utils。如果您将整个馈送粘贴在响应中,它将尝试在每次往返时来回发送它,并快速超过最大有效负载以进行sproc调用或返回。您可以使用原始SDK,并确保在返回另一个呼叫之前删除Feed内容。

答案 1 :(得分:0)

好吧,我已经完成了你的回答和我在GitHub上找到的样本存储过程的组合

使用这两个作为参考,我重写了我的'试用存储过程,如下:

function trialRun(startDateTime, endDateTime, continuationToken)
{
    var context = getContext();
    var collection = context.getCollection();
    var maxResult = 1000;   // Value from sample = 25

    var sqlString = "select p.id, p.ClientId, p.ActionType, a.Action, a.TimeStamp "
                   + "from History p"
                   + "     join a in p.Actions "
                   + "where a.TimeStamp >= '" + startDateTime + "' "
                   + "  and a.TimeStamp <= '" + endDateTime + "' ";
    var result = null;

    tryQuery(continuationToken, sqlString);

    // Helper method to check for max result and call query.
    function tryQuery(nextContinuationToken)
    {
        var responseOptions = { continuation: nextContinuationToken, pageSize : maxResult };

        // In case the server is running this script for long time/near timeout, it would return false,
        // in this case we set the response to current continuation token, 
        // and the client will run this script again starting from this continuation.
        // When the client calls this script 1st time, is passes empty continuation token.
        if (result >= maxResult || !query(responseOptions)) { setBody(nextContinuationToken); }
    }

    function query(responseOptions)
    {
        var resultSet = collection.queryDocuments(collection.getSelfLink(), sqlString, responseOptions, onReadDocuments);

        return resultSet;
    }

    function onReadDocuments(err, docFeed, responseOptions)
    {
        if (err)
        {
            throw 'Error while reading document: ' + err;
        }

        // Increament the number of documents counted so far.
        result += JSON.Stringify(docFeed);

        // If there is continuation, call query again with it, 
        // otherwise we are done, in which case set continuation to null.
        if (responseOptions.continuation)
        {
            tryQuery(responseOptions.continuation);
        }
        else
        {
            setBody(null);
        }
    }

    // Set response body: use an object the client is expecting (2 properties: result and continuationToken).
    function setBody(continuationToken)
    {
        var body = { trialRun: result, continuationToken: continuationToken };
        getContext().getResponse().setBody(body);
    }
}

现在我收到的结果集包含缺少的10条记录。我将以同样的方式修改我的实际程序。