如何在服务器端触发器内同步读取Azure DocumentDb集合中的数据?

时间:2016-05-12 16:28:10

标签: javascript azure azure-cosmosdb

我正在尝试在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);

1 个答案:

答案 0 :(得分:1)

在返回之前,它将自动等待所有待处理的异步操作完成,失败或超时。你有什么是接近的。我唯一能看到的是你在改变request.setBody(docToCreate)之后再也没有打电话给docToCreate

那就是说,我不能100%确定这种方法是安全的。触发器,sproc或UDF内的所有操作都是原子的,但我不确定预触发和写操作的组合是否是原子的。风险是两个同时写入将运行并完成触发器部分,这将给予它们相同的.Version。您可能不得不要求DocumentDB产品经理确认这一点。他们在这里闲逛,所以他们可以在这里回复。

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

您可能还会考虑创建一个文档,其id您的硬编码类似于' LAST_VERSION'保留上次使用的版本。这意味着每次写入都会导致读取+两次写入(一次用于文档,一次用于更新此文档),但它可能比您的查询+一种写入方法更有效。您可以在一个sproc中执行所有这些操作,也可以使用预触发器(以获取' LAST_VERSION' +写入操作+后触发器(以更新' LAST_VERSION'文档)取决于产品经理对原子性的评价。

关于当前方法的另一个警告......确保Version字段上索引的精度设置为-1(最大精度)。