Search documentationEsc

Unique key policies

Enforce uniqueness within a partition with [UniqueKey] attributes.

Azure Cosmos DB supports unique key policies — properties that, in combination, must be unique within a partition. You can define multiple policies per partition.

What unique keys do

Imagine you store people in a Cosmos container partitioned by /county. You want at most one person per county with the same name and age. That’s a unique key built from firstName and age, scoped to the /county partition.

Single key policy

Decorate the relevant properties with [UniqueKey(propertyPath: "...")]:

using Microsoft.Azure.CosmosRepository;
using Microsoft.Azure.CosmosRepository.Attributes;
namespace Sample.Models;
public class Person : Item
{
[UniqueKey(propertyPath: "/firstName")]
public string FirstName { get; set; }
[UniqueKey(propertyPath: "/age")]
public int Age { get; set; }
public string County { get; set; }
public string FavouriteColor { get; set; }
protected override string GetPartitionKeyValue() => County;
public Person(string firstName, int age, string county, string favouriteColor)
{
FirstName = firstName;
Age = age;
County = county;
FavouriteColor = favouriteColor;
}
}

The following sequence shows when the policy fires:

var repository = serviceProvider.GetRequiredService<IRepository<Person>>();
var bobInYorkshire = new Person("bob", 20, "Yorkshire", "Blue");
await repository.CreateAsync(bobInYorkshire);
// Different partition — allowed.
var bobInMerseyside = new Person("bob", 20, "Merseyside", "Green");
await repository.CreateAsync(bobInMerseyside);
// Same partition, different age — allowed.
var bobInYorkshireWhoIs22 = new Person("bob", 22, "Yorkshire", "Red");
await repository.CreateAsync(bobInYorkshireWhoIs22);
try
{
// Same partition, same name + age — violates the policy.
var anotherBob = new Person("bob", 20, "Yorkshire", "Yellow");
await repository.CreateAsync(anotherBob);
}
catch (CosmosException e) when (e.StatusCode == HttpStatusCode.Conflict)
{
// Unique-key violation
}

Multiple key policies

You can group attributes into different policies by giving them named keys. Below, firstName + age form one policy and favouriteColor forms a second:

using Microsoft.Azure.CosmosRepository;
using Microsoft.Azure.CosmosRepository.Attributes;
namespace Sample.Models;
public class Person : Item
{
[UniqueKey(keyName: "nameAndAgePolicyKeyName", propertyPath: "/firstName")]
public string FirstName { get; set; }
[UniqueKey(keyName: "nameAndAgePolicyKeyName", propertyPath: "/age")]
public int Age { get; set; }
public string County { get; set; }
[UniqueKey(keyName: "favouriteColorPolicyKeyName", propertyPath: "/favouriteColor")]
public string FavouriteColor { get; set; }
protected override string GetPartitionKeyValue() => County;
public Person(string firstName, int age, string county, string favouriteColor)
{
FirstName = firstName;
Age = age;
County = county;
FavouriteColor = favouriteColor;
}
}
var repository = serviceProvider.GetRequiredService<IRepository<Person>>();
var bobInYorkshire = new Person("bob", 20, "Yorkshire", "Blue");
await repository.CreateAsync(bobInYorkshire);
// Different partition — allowed.
var bobInMerseyside = new Person("bob", 20, "Merseyside", "Green");
await repository.CreateAsync(bobInMerseyside);
// Same partition, different age — allowed.
var bobInYorkshireWhoIs22 = new Person("bob", 22, "Yorkshire", "Red");
await repository.CreateAsync(bobInYorkshireWhoIs22);
try
{
// Fred has a unique name+age, but "Red" already exists in Yorkshire.
var fredInYorkshireWhoAlsoLikeRed = new Person("fred", 30, "Yorkshire", "Red");
await repository.CreateAsync(fredInYorkshireWhoAlsoLikeRed);
}
catch (CosmosException e) when (e.StatusCode == HttpStatusCode.Conflict)
{
// Violation of the favouriteColorPolicyKeyName policy
}