CosmosDB CreateDocumentQuery с EnableCrossPartitionQuery не возвращает результаты, но возвращает, если указано PartitionKey

У меня проблема, когда, если я укажу ключ раздела для определенного запроса, я получу ожидаемую запись. Однако, если я не укажу ключ раздела и просто установлю для EnableCrossPartitionQuery значение true, он не вернет / не найдет никаких документов.

На самом деле это работает должным образом на одной из моих баз данных Cosmos DB, но не на другой. Те же записи / документы.

Я использую следующую настройку

  1. Пакет NuGet Microsoft.Azure.DocumentDB версии 2.3.0

  2. Коллекция Cosmos DB с неограниченной емкостью (с PartitionKey = ApplicationId)

  3. Три очень простых документа в базе данных / коллекции, созданные вручную с помощью обозревателя хранилищ Azure.

Мой код выглядит довольно просто, как показано ниже. Если вызывающий GetDocuments передает значение для partitionKey, я указываю его в запросе через FeedOptions. В противном случае я устанавливаю EnableCrossPartitionQuery в FeedOptions.

Документы в базе данных / коллекции, которая действительно работает, такие же, как и документы в базе данных / коллекции, которая не работает.

Я создал коллекции таким же образом, с тем же ключом раздела (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
}

Есть идеи, почему это не работает?


person GR7    schedule 20.04.2019    source источник


Ответы (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;
}
person Nick Chapsas    schedule 21.04.2019
comment
Спасибо, @Nick Chapsas. - person GR7; 23.04.2019