#azure #azure-cosmosdb #azure-cosmosdb-sqlapi
#azure #azure-cosmosdb #azure-cosmosdb-sqlapi
Вопрос:
У меня проблема, когда, если я укажу ключ раздела для определенного запроса, я получу ожидаемую запись. Однако, если я не укажу ключ раздела и просто установлю для EnableCrossPartitionQuery значение true, он не вернет / не найдет никаких документов.
Это действительно работает, как ожидалось, на одной из моих космических баз данных, но не на другой. Те же записи / документы.
Я использую следующую настройку
-
Майкрософт.Azure.DocumentDB NuGet пакет версии 2.3.0
-
Коллекция Cosmos DB с неограниченной емкостью (с PartitionKey = applicationId)
-
Три очень простых документа в базе данных / коллекции, созданные вручную с помощью Azure Storage Explorer
Мой код выглядит так, как показано ниже, довольно просто. Если вызывающий 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
}
Есть идеи, почему это не работает?
Ответ №1:
Ваш код неверен. Ваша ошибка заключается в этой проверке:
if (queryData.Any())
Вы возвращаетесь до того, как фактически получите все данные обратно.
Причина, по которой ваш код работает с ключом раздела, заключается в том, что вы ориентируетесь на один физический раздел (через логический раздел), и содержащиеся в нем данные меньше, чем MaxItemCount или RequestOptions
предоставленный вами объект.
Cosmos DB возвращает только результаты с разбивкой на страницы, и для этих значений необходимо вызывать каждый физический раздел, иногда кратно каждому разделу, и в некоторых случаях итерация может возвращать 0 данных, но в следующей может быть несколько. Вы должны ExecuteNextAsync
, пока HasMoreResults
значение false .
Добавление цикла 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;
}
Комментарии:
1. Спасибо @Nick Chapsas.