Skip to content

Key Paths

Every Item has one or more Key Paths. A Key Path is like an address for your Item – it tells StatelyDB exactly where to find (or where to put) the item. Key Paths are crucial for efficiently organizing and retrieving your data—they play a similar role to primary keys and indexes in other database systems, and can be used to easily fetch many items of different kinds with a single List operation.

Key Paths are composed of one or more segments, each in the format namespace-ID. They’re designed to be similar to file paths or URLs, which makes them intuitive to work with. In the example above, Customer has a key path of /cust-:id. An Order Item might have a key path that incorporates the Customer it belongs to:

Diagram of a key path, with the segments highlighted as "key segment", and the namespace and ID segments also called out

An individual Order would fill in this “key path template” with real values, so it might look something like /cust-1234/order-6.

The namespace portion of each key path segment helps you distinguish between different types of items, but they don’t need to be the same as the item type name. For example, if your Store has two item types, Customer and Order, which both have UUID id fields, you might choose the key paths /cust-:id and /ord-:id. If you didn’t have the namespace, the two keys would collide and you wouldn’t be able to tell which was a Customer and which was an Order just by looking at them. Note that key paths make up part of the storage of items, so it can be helpful to choose short namespaces.

The ID portion of each key path segment may be a string, number, or binary data (base64-encoded). An example of binary data is a UUID - Stately stores standard 128-bit UUIDs as 16-byte binary instead of the 36-byte string format, to save space.

Example Key Paths

Key PathItem TypeID
/cust-p05olqcFSfC6zOqEojxT9gCustomeruuid (Base64)
/ord-2Orderuint64
/cust-p05olqcFSfC6zOqEojxT9g/ord-2Orderuint64
/li-B0881XTCR3LineItemstring

Key Paths provide a lot of flexibility in how to structure your data. You can use them to create hierarchies, represent relationships between different types of data, and more.

Child Items: Building Relationships

Key Paths allow us to create parent-child relationships between Items by adding multiple segments, as shown above in the Order example. We call Items that are nested under other Items “Child Items”. Child Items are particularly useful when you have data that logically belongs together, but you want to be able to access or modify individual parts independently. For example, you can update or append individual child Items instead of updating one huge Item (like adding an Order to a Customer). Or you might want to retrieve only a subset of child items (like listing out only the Orders from the last month).

Example

Imagine you want to store a customer’s orders as Child Items of their customer profile. Here’s how that might look:

1
export const Order = itemType("Order", {
2
keyPath: [
3
"/order-:id",
4
"/customer-:id/order-:id",
5
],
6
fields: {
7
id: { type: uint, fieldNum: 1, initialValue: "sequence" },
8
customerId: { type: uuid, fieldNum: 2 },
9
zipCode: { type: string, fieldNum: 3 },
10
created: {
11
type: timestampMilliseconds,
12
fieldNum: 4,
13
fromMetadata: "createdAtTime",
14
},
15
},
16
});

You can continue to nest more Items as children of these child Items. For example, you could store individual line Items for the order as child Items with nested key paths:

1
export const LineItem = itemType("LineItem", {
2
keyPath: "/cust-:customerId/ord-:orderId/li-:upc",
3
fields: {
4
upc: { type: string, fieldNum: 1 },
5
customerId: { type: uuid, fieldNum: 2 },
6
orderId: { type: uuid, fieldNum: 3 },
7
name: { type: string, fieldNum: 4 },
8
quantity: { type: uint, fieldNum: 5 },
9
created: {
10
type: timestampMilliseconds,
11
fieldNum: 6,
12
fromMetadata: "createdAtTime",
13
},
14
},
15
});

With this structure, you can access all orders and their line items for a specific customer in a single operation, by listing all Items that start with /cust-p05olqcFSfC6zOqEojxT9g/order (assuming the customer ID is p05olqcFSfC6zOqEojxT9g).

Multiple Key Paths

Each Item Type can have multiple key path templates. This works much like an index in other databases—each key path gives you an opportunity to access the data in a different way. StatelyDB stores a separate copy of the Item under each key path, and keeps them in sync automatically. For example, look back at our Order Item Type:

1
export const Order = itemType("Order", {
2
keyPath: [
3
"/order-:id",
4
"/customer-:id/order-:id",
5
],
6
fields: {
7
// ...
8
}
9
});

Because this has two key paths, you can Get an order with only its ID using the /order-:id key path, or List all orders for a customer using the /customer-:id/order-:id key path.

Group Keys

The first segment of a key path is special - it is called the Group Key. Read about Groups for more info on why that’s important.

Learn More

There’s more information about how to choose and structure your key paths in the Schema documentation: Key Paths.