Search code examples
c#azureasp.net-coreazure-cosmosdbdatabase-partitioning

Partition Key for Cosmos DB


I am building RESTful API using ASP.NET Core with Cosmos DB. There's a GetItemById request that needs a partition key.

 public static async Task<T> GetItemAsync(string itemId, string name)
 {
     try
     {
         Document document =
             await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, itemId),
                 new RequestOptions() { PartitionKey = new PartitionKey(name) });

         return (T)(dynamic)document;
     }
     catch (DocumentClientException e)
     {
         if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
         {
             return null;
         }
         else
         {
             throw;
         }
     }
 }

The GetByIdAsync() function calls this GetItemAsync() method.

[HttpGet("{itemId}")]
public async Task<IActionResult> GetByIdAsync(string itemId, string name)
{
    var item = await DocumentDBRepository<TodoItem>.GetItemAsync(itemId, name);
    if (item == null)
    {
        return NotFound();
    }
    return new ObjectResult(item);
}

The URL would be http://localhost:54084/api/todo/f323307b-142f-46f3-9072-12f41cc74e87

My Azure CosmosDB container looks like this: enter image description here

But when I run this, it gave me an error with

Microsoft.Azure.Documents.DocumentClientException: Partition key provided either doesn't correspond to definition in the collection or doesn't match partition key field values specified in the document.


Solution

  • In Cosmos DB, the primary key is the combination of partition key and the row key ("id"). The combination of the two uniquely identifies a row - not the "id" alone. So you need to specify the value of Name in the partition key to find the item (not null).

    If your app doesn't have a natural PK, then you should consider setting "/id" as the partition key (and pass the value for both id and partition key)