对于一个应用程序,我创建了一个在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;页面获取数据的示例代码?
答案 0 :(得分:1)
首先推荐。如果你所做的只是一个查询,你最好使用客户端SDK和/或documentdb-utils(这只是Azure提供的SDK的包装器)。 sproc内部的查询不会使用辅助节点并限制整体吞吐量。来自客户端SDK的查询将使用辅助节点,并且性能更高。另一方面,如果你将一堆行聚合到一个结果,那么sproc可能是最好的,具体取决于。
也就是说,即使你将聚合移动到sproc中,你也会遇到同样的问题。因此,要解决这个问题,您可能需要查看documentdb-utils中的一个示例。从countDocuments sproc开始。此外,您可能希望了解用于编写here找到的可重新启动的sprocs的模式。
我怀疑你缺少的关键概念是在NoSQL世界中,特别是在JavaScript中,你需要异步思考并编写代码,以便可以中断和重新启动它。
假设您可以将聚合需求转移到sproc中,那么您所需的更改包括:
系统停止接受请求时不要抛出错误。而是保存当前的执行状态,并包含一个指示符,需要重新启动sproc。我链接到的countDocuments示例使用stillQueueing
。如果你使用documentdb-utils,那将告诉它sproc没有完成,需要再次调用。
在queryDocuments()
requestOptions
的{{1}}来电中添加第三个参数,并将pageSize
设置为1000. 1000足够大,您将无法获得大量的回合跳转到数据库,但足够小,你可以在系统返回false之后处理它,表明它不再排队请求但是在强制超时之前。
当页面进入您的聚合时,会将结果累积到您将返回的正文中。
您无需JSON.stringify()
回复。他们的系统将负责编组纯JavaScript对象。
在任何情况下,都不要将整个Feed添加到您的回复中。只有你的聚合。
捕获在回调的第三个options
参数中找到的延续令牌,并将其与您的回复一起传回。
如果你真的想使用一个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条记录。我将以同样的方式修改我的实际程序。