阅读可能不存在的 Azure DocumentDB 文档

本文关键字:Azure DocumentDB 文档 不存在 | 更新日期: 2023-09-27 18:35:22

我可以像这样从 Azure DocumentDB 查询单个文档:

var response = await client.ReadDocumentAsync( documentUri );

如果文档不存在,这将引发 DocumentClientException。在我的程序中,我遇到文档可能存在也可能不存在的情况。有没有办法在不使用 try-catch 的情况下查询文档,并且不对服务器进行两次往返,首先查询文档,然后检索文档(如果存在)?

阅读可能不存在的 Azure DocumentDB 文档

可悲的是,没有其他方法,要么处理异常,要么进行 2 次调用,如果您选择第二条路径,这是一种性能驱动的检查文档是否存在的方法:

public bool ExistsDocument(string id)
{
    var client = new DocumentClient(DatabaseUri, DatabaseKey);
    var collectionUri = UriFactory.CreateDocumentCollectionUri("dbName", "collectioName");
    var query = client.CreateDocumentQuery<Microsoft.Azure.Documents.Document>(collectionUri, new FeedOptions() { MaxItemCount = 1 });
    return query.Where(x => x.Id == id).Select(x=>x.Id).AsEnumerable().Any(); //using Linq
}

客户端应该在所有数据库访问方法之间共享,但我在那里创建它是为了有一个自动访问示例。

new FeedOptions () {MaxItemCount = 1}将确保查询将针对 1 个结果进行优化(我们实际上不需要更多)。

Select(x=>x.Id)将确保不返回其他数据,如果您未指定它并且文档存在,它将查询并返回其所有信息。

您专门查询给定的文档,当找不到特定文档时,ReadDocumentAsync将抛出该DocumentClientException(在状态代码中返回 404)。此处对此进行了记录。通过捕获异常(并看到它是 404),您将不需要两次往返。

若要解决此异常,需要使用 CreateDocumentQuery() 进行查询而不是离散读取。然后,您只需获得一个可以枚举的结果集(即使该结果集为空)。例如:

var collLink = UriFactory.CreateDocumentCollectionUri(databaseId, collectionId);
var querySpec = new SqlQuerySpec { <querytext> };
var itr = client.CreateDocumentQuery(collLink, querySpec).AsDocumentQuery();
var response = await itr.ExecuteNextAsync<Document>();
foreach (var doc in response.AsEnumerable())
{
    // ...
}

使用这种方法,您将不会得到任何响应。在特定情况下,您将添加一个 WHERE 子句以按其 id 查询特定文档,您将获得零个结果或一个结果。

使用 CosmosDB SDK 版本 3 是可能的。您可以检查容器中是否存在项目,并通过使用 Container.ReadItemStreamAsync<T>(string id, PartitionKey key) 并检查response.StatusCode来获取它:

using var response = await container.ReadItemStreamAsync(id, new PartitionKey(key));
if (response.StatusCode == HttpStatusCode.NotFound)
{
    return null;
}
if (!response.IsSuccessStatusCode)
{
    throw new Exception(response.ErrorMessage);
}
using var streamReader = new StreamReader(response.Content);
var content = await streamReader.ReadToEndAsync();
var item = JsonConvert.DeserializeObject(content, stateType);

但是,这种方法有一个缺点。您需要手动反序列化项目。