具有EnableCrossPartitionQuery的CosmosDB CreateDocumentQuery不会返回结果,但是如果指定PartitionKey

时间:2019-04-20 23:41:25

标签: azure azure-cosmosdb azure-cosmosdb-sqlapi

我遇到一个问题,如果我为特定查询指定了分区键,那么我将获得期望的记录。但是,如果我未指定分区键,而只是将EnableCrossPartitionQuery设置为true,它将不会返回/查找任何文档。

这实际上在我的一个Cosmos DB上可以正常工作,但在另一个DBs上却没有。相同的记录/文件。

我正在使用以下设置

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

  2. 容量不受限制的Cosmos DB集合(其中PartitionKey = ApplicationId)

  3. 通过Azure Storage Explorer手动创建的关于数据库/集合的三个非常简单的文档

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

有效的数据库/集合上的文档与无效的数据库/集合上的文档相同。

我以相同的方式,使用相同的分区键(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
}

有什么想法为什么行不通?

1 个答案:

答案 0 :(得分:1)

您的代码错误。您的支票有误:

if (queryData.Any())

您要先返回,然后才能真正获取所有数据。

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

Cosmos DB仅返回分页结果,它需要为每个物理分区调用这些值,有时是每个分区的倍数,在某些情况下,迭代可能返回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;
}