|
| 1 | +# Partition Keys in the Python SDK for Azure Cosmos DB |
| 2 | + |
| 3 | +Partition keys determine how your data is logically distributed across physical partitions for scalability and performance in Azure Cosmos DB. Selecting an appropriate partition key is one of the most important design decisions you will make when modeling data. |
| 4 | + |
| 5 | +For general best practices, see: |
| 6 | +- [Choosing a partition key](https://learn.microsoft.com/azure/cosmos-db/partitioning-overview#choose-a-partition-key) |
| 7 | + |
| 8 | +--- |
| 9 | +## Defining a Partition Key on Container Creation |
| 10 | +When you create a container you must define its partition key path (e.g. `/partition_key`). You may also specify the hashing algorithm kind and version (e.g. Hash v2). Use the `PartitionKey` class: |
| 11 | + |
| 12 | +```python |
| 13 | +from azure.cosmos import PartitionKey |
| 14 | + |
| 15 | +container = database.create_container_if_not_exists( |
| 16 | + id="items", |
| 17 | + partition_key=PartitionKey(path="/partition_key", kind="Hash", version=2) |
| 18 | +) |
| 19 | +``` |
| 20 | + |
| 21 | +--- |
| 22 | +## Supplying Partition Key Values for Container Operations |
| 23 | +You can provide the partition key value in two ways for container APIs depending on the operation: |
| 24 | + |
| 25 | +1. Pass the value explicitly via the `partition_key` parameter: |
| 26 | + ```python |
| 27 | + document = { |
| 28 | + 'id': 'item_id', |
| 29 | + 'partition_key': 'partition_key_value', |
| 30 | + 'otherProperty': 'value' |
| 31 | + } |
| 32 | + container.read_item(item=document['id'], partition_key=document['partition_key']) |
| 33 | + ``` |
| 34 | +2. Embed the partition key property in the document you supply via `body` (the SDK extracts it): |
| 35 | + ```python |
| 36 | + doc = {"id": "item_id", "partition_key": "partition_key_value", "otherProperty": "value"} |
| 37 | + container.create_item(body=doc) |
| 38 | + ``` |
| 39 | + |
| 40 | +--- |
| 41 | +## Valid Partition Key Value Types |
| 42 | +The SDK accepts a broad set of types for a single (logical) partition key component: |
| 43 | +```python |
| 44 | +Union[None, bool, float, int, str, Type[NonePartitionKeyValue], Type[NullPartitionKeyValue], Sequence[Union[str, int, float, bool, None]] |
| 45 | +``` |
| 46 | +These include two special sentinel values that disambiguate absence vs explicit null: |
| 47 | + |
| 48 | +- **`NonePartitionKeyValue`**: Indicates the partition key property is **absent** in the stored item (the property was omitted). |
| 49 | +- **`NullPartitionKeyValue`**: Indicates the partition key property exists and its JSON value is **null**. |
| 50 | + |
| 51 | +> Why two sentinels? Python `None` can mean either "explicitly null" *or* "perform a cross-partition operation" depending on the API. These sentinels remove ambiguity. |
| 52 | + |
| 53 | +--- |
| 54 | +## Creating Items with Special Partition Key States |
| 55 | + |
| 56 | +### Item with NO partition key property (use `NonePartitionKeyValue` for reads) |
| 57 | +Omit the property when creating the item: |
| 58 | +```python |
| 59 | +import azure.cosmos.partition_key as pk |
| 60 | + |
| 61 | +doc = {"id": "item_without_pk"} # no partition_key field |
| 62 | +container.create_item(body=doc) |
| 63 | + |
| 64 | +retrieved = container.read_item(item="item_without_pk", partition_key=pk.NonePartitionKeyValue) |
| 65 | +``` |
| 66 | + |
| 67 | +### Item with an explicit JSON null partition key (use `NullPartitionKeyValue` OR `None` for most point ops) |
| 68 | +Set the property to `None` in the Python dict: |
| 69 | +```python |
| 70 | +doc = {"id": "item_with_null_pk", "partition_key": None} |
| 71 | +container.create_item(body=doc) |
| 72 | + |
| 73 | +# Reads (point operations) – either works |
| 74 | +a = container.read_item(item="item_with_null_pk", partition_key=None) # treated as null value |
| 75 | +b = container.read_item(item="item_with_null_pk", partition_key=pk.NullPartitionKeyValue) |
| 76 | +``` |
| 77 | + |
| 78 | +--- |
| 79 | +## Choosing the Correct Value When Calling APIs |
| 80 | +| Scenario | Use This Partition Key Argument | |
| 81 | +|----------|---------------------------------| |
| 82 | +| Item lacked the partition key property | `NonePartitionKeyValue` | |
| 83 | +| Item has partition key explicitly null (JSON `null`) – point read / replace / delete | `None` OR `NullPartitionKeyValue` | |
| 84 | +| Query constrained to the null value | `NullPartitionKeyValue` (NOT plain `None`) | |
| 85 | +| Cross-partition query (scan all logical partitions) | `None` | |
| 86 | + |
| 87 | +--- |
| 88 | +## Queries with None Caveat |
| 89 | +For `query_items` and `query_conflicts`: |
| 90 | +- Passing `partition_key=None` signals a **cross-partition** query. It does **not** filter to items whose key is null. |
| 91 | +- To restrict to items whose partition key value is JSON null, you must pass `partition_key=pk.NullPartitionKeyValue`. |
| 92 | + |
| 93 | +Example (query only null-key items): |
| 94 | +```python |
| 95 | +import azure.cosmos.partition_key as pk |
| 96 | + |
| 97 | +results = list(container.query_items( |
| 98 | + query="SELECT * FROM c WHERE c.type = 'Example'", |
| 99 | + partition_key=pk.NullPartitionKeyValue |
| 100 | +)) |
| 101 | +``` |
| 102 | + |
| 103 | +--- |
| 104 | +## Summary Decision Guide |
| 105 | +- Omit property to create an item with *no* partition key value; later read with `NonePartitionKeyValue`. |
| 106 | +- Set property to `None` to create an item whose partition key value is JSON null; read with `None` or `NullPartitionKeyValue`. |
| 107 | +- Use `NullPartitionKeyValue` for queries targeting the null value. |
| 108 | +- Use plain `None` for cross-partition queries. |
| 109 | + |
| 110 | +--- |
| 111 | +## Related Links |
| 112 | +- [Azure Cosmos DB partitioning overview](https://learn.microsoft.com/azure/cosmos-db/partitioning-overview) |
| 113 | +- [SDK samples](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/cosmos/azure-cosmos/samples/README.md) |
| 114 | + |
| 115 | +--- |
0 commit comments