【问题标题】:How to synchronously read data from Azure DocumentDb collection inside a server-side trigger?如何从服务器端触发器内的 Azure DocumentDb 集合中同步读取数据?
【发布时间】:2016-05-12 16:28:09
【问题描述】:

我正在尝试在 Azure DocumentDb 集合上实现触发器,该触发器应该自动增加正在插入的文档版本。触发器被创建为预触发器。 我面临的挑战是集合类似乎没有提供用于查询数据的同步 API。我的触发器计划是查询现有文档,获取最高版本,递增,并将 +1 值分配给正在插入集合中的文档。但由于查询的结果只能异步获得,到那时我的触发器已完成,文档未修改地插入。
如何等待查询结果? 这是我当前触发器的样子:

// TRIGGER Auto increment version
    function autoIncrementVersion() {
      var collection = getContext().getCollection();
      var request = getContext().getRequest();
      var docToCreate = request.getBody();

      // Reject documents that do not have a name property by throwing an exception.
      if (!docToCreate.Version) {
        throw new Error('Document must include a "Version" property.');
      }

      var lastVersion;

      var filter = "SELECT TOP 1 d.Version FROM CovenantsDocuments d ORDER BY d.Version DESC";

      var result = collection.queryDocuments(collection.getSelfLink(), filter, {},
                function (err, documents, responseOptions) {
                    if (err) throw new Error("Error: " + err.message);
                    if (documents.length != 1 || !documents[0]) {
                      lastVersion = 0;
                    } else {
lastVersion  = documents[0];
}
                   //By the time we reach this line, our trigger has already completed?
                    docToCreate.Version = lastVersion + 1;
                });
      if (!result) throw "Unable to read last version of the document";

    }

更新:问题在于我提交请求的方式。看起来默认情况下不会触发触发器,它们的名称需要作为请求的参数显式提供。 在我的情况下,直到我将客户端代码更改为此触发器才触发:

RequestOptions options = new RequestOptions
{
    PreTriggerInclude = new[] { "autoIncrementVersion"}
};
client.CreateDocumentAsync(url, document, options);

【问题讨论】:

    标签: javascript azure azure-cosmosdb


    【解决方案1】:

    它会自动等到所有挂起的异步操作完成、失败或超时后再返回。你所拥有的很接近。我唯一能看到的就是你在更改docToCreate 后永远不会调用request.setBody(docToCreate)

    也就是说,我不能 100% 确定这种方法是否安全。触发器、存储过程或 UDF 内的所有操作都是原子的,但我不确定预触发器和写入操作的组合是否是原子的。风险在于两个同时写入将同时运行并完成触发器部分,这将为它们提供相同的 .Version。您可能需要请 DocumentDB 产品经理确认这一点。他们在这里闲逛,所以他们可以在这里回应。

    如果您发现它不是原子的,那么您可以将所有内容(读取以查找最新版本并写入)移动到存储过程(sproc)中。

    您还可以考虑创建一个单独的文档,您可以将其id 硬编码为“LAST_VERSION”之类的内容,以保存上次使用的版本。这意味着每次写入都会导致一次读取 + 两次写入(一次用于文档,一次用于更新此文档),但它可能比您的查询 + 一次写入方法更有效。您可以在一个存储过程中完成所有这些操作,或者您可以使用预触发(获取“LAST_VERSION”+写入操作+后触发(更新“LAST_VERSION”文档)),具体取决于产品经理对原子性的看法。

    关于当前方法的另一个注意事项...确保版本字段上的索引精度设置为 -1(最大精度)。

    【讨论】:

    • Larry,非常感谢,你的回答听起来像是一个解决方案,我明天试试 request.setBody(),这一定是我的触发器没有更新版本的原因。
    • 另外,将研究原子性方面。并确保版本字段的精度是正确的。不过,我并不清楚您回答中的一个细节 - 关于抛出 if documents.length > 1 的问题。这是我第一次尝试 DocumentDb 查询语法,所以我是古玩,TOP 1 关键字不能保证我不能获得超过 1 条记录?再次感谢!
    • 你是对的,不需要与 TOP 一起投掷。我在想它会确认没有两个文档具有相同的版本,但它不会那样做。我把它编辑了。
    • 事实证明,setBody() 调用对我来说并没有什么不同。真正的问题在于我提交请求的方式。
    • 我有一个问题。我们知道存储过程是 ACID 原子的,但它们是同步的吗?是否有某种信号量可以对存储过程的调用进行排队?我之所以问是因为我想添加一些存储过程来更新某些项目,但是即使是原子的,我也担心如果同一存储过程的多个实例同时执行,一个会成功,但如果他们尝试更新项目,其他实例可能会失败在一审之后做到了。 sprocs 是同步的吗?他们排好队了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多