带有 EnableCrossPartitionQuery 的 CosmosDB CreateDocumentQuery 没有 return 结果,但如果指定了 PartitionKey

CosmosDB CreateDocumentQuery with EnableCrossPartitionQuery does not return results but does if specifying the PartitionKey

我有一个问题,如果我为特定查询指定分区键,我将得到我期望的记录。但是,如果我不指定分区键而只是将 EnableCrossPartitionQuery 设置为 true,它不会 return/find 任何文档。

这实际上在我的一个 Cosmos DB 上按预期工作,但在另一个 Cosmos DB 上却不行。相同 records/documents.

我正在使用以下设置

  1. Microsoft.Azure.DocumentDB NuGet 包版本 2.3.0

  2. 具有无限容量的 Cosmos DB 集合(PartitionKey = ApplicationId)

  3. DB/Collection 上的三个非常简单的文档,通过 Azure 存储资源管理器手动创建

我的代码如下所示,相当简单。如果 GetDocuments 的调用者为 partitionKey 传递了一个值,那么我通过 FeedOptions 在查询中指定它。否则,我在 FeedOptions 上设置了 EnableCrossPartitionQuery。

Database/Collection 上有效的文档与 DB/Collection 上无效的文档相同。

我以相同的方式使用相同的分区键 (ApplicationId) 创建了集合

public async Task<IEnumerable<T>> GetDocuments<T>(Expression<Func<T, bool>> predicate, object partitionKey = null)
{
    IDocumentQuery<T> queryDetails = QueryDocument<T>(predicate, partitionKey);

    var queryData = await queryDetails.ExecuteNextAsync<T>();

    if (queryData.Any())
    {
        return queryData;
    }

    return default(IEnumerable<T>);
}

private IDocumentQuery<T> QueryDocument<T>(Expression<Func<T, bool>> predicate, object partitionKey = null)
{
    FeedOptions feedOptions;

    if (partitionKey == null)
    {
        feedOptions = new FeedOptions { EnableCrossPartitionQuery = true };
    }
    else
    {
        feedOptions = new FeedOptions { PartitionKey = new PartitionKey(partitionKey) };
    }

    var query = _client.CreateDocumentQuery<T>(DocumentCollectionUri, feedOptions);

    var queryDetails = query.Where(predicate).AsDocumentQuery();

    return queryDetails;
}

文档如下所示:

{
"id": "1",
"HubName": "abxyz-hub",
"ClientId": "abxyz",
"ApplicationId": 1,
"ApplicationName": "My App Name",
"_rid": "hSkpAJde99IBAAAAAAAAAA==",
"_self": "dbs/hSkpAA==/colls/hSkpAJde99I=/docs/hSkpAJde99IBAAAAAAAAAA==/",
"_etag": "\"53007677-0000-0100-0000-5cbb3c660000\"",
"_attachments": "attachments/",
"_ts": 1555774566
}

知道为什么这不起作用吗?

您的代码有误。您的错误在于此检查:

if (queryData.Any())

在您真正取回所有数据之前,您正在 returning。

您的代码使用分区键的原因是因为您的目标是一个物理分区(通过逻辑分区)并且包含的​​数据少于您提供的 MaxItemCount 或 RequestOptions 对象。

Cosmos DB 只有 returns 分页结果,它需要为这些值调用每个物理分区,有时是每个分区的倍数,在某些情况下迭代可能 return 0 数据但是下一个可能有一些。您必须 ExecuteNextAsync 直到 HasMoreResults 为假。

添加一个 while 循环以从您的跨分区查询将命中的所有物理分区中获取所有分页结果将解决问题:

代码如下:

public async Task<IEnumerable<T>> GetDocuments<T>(Expression<Func<T, bool>> predicate, object partitionKey = null)
{
    IDocumentQuery<T> documentQuery = QueryDocument<T>(predicate, partitionKey);

    var results = new List<T>();

    while(documentQuery.HasMoreResults)
    {
        var docs = await documentQuery.ExecuteNextAsync<T>();    
        results.AddRange(docs)
    }

    return results;
}

private IDocumentQuery<T> QueryDocument<T>(Expression<Func<T, bool>> predicate, object partitionKey = null)
{
    FeedOptions feedOptions;

    if (partitionKey == null)
    {
        feedOptions = new FeedOptions { EnableCrossPartitionQuery = true };
    }
    else
    {
        feedOptions = new FeedOptions { PartitionKey = new PartitionKey(partitionKey) };
    }

    var query = _client.CreateDocumentQuery<T>(DocumentCollectionUri, feedOptions);

    var queryDetails = query.Where(predicate).AsDocumentQuery();

    return queryDetails;
}