In cosmosdb, should I reference other documents using id, resource id, or self link?

Viewed 2216

I'm working on designing my CosmosDB collections and deciding what I will and won't nest in a single document, etc. There's no way around it, though - there will be scenarios where I need to reference documents from one collection within another.

I see that in CosmosDB there are several ways to identify a document - id, resource id and self link. It looks like id is enforced to be unique and can either be set by server or to whatever you want it to be. Next, it looks like resource id is always auto generated by the server and is guaranteed to be unique as well. Last, it looks like self link is built up using the id of the database, collection and document, meaning it'll also be unique. I see three different unique keys, all having their own uses and semantics.

  1. Which one should I use internally when referencing other documents?
  2. What about referencing documents in different collections - would resource id or self link be more "universal identifier" than just id?
2 Answers
  • DO use natural key for id values, if possible.
  • DO use id for cross-document references.
  • DO use names for collection/database references.
  • DO NOT use _rid or _selflink when you need a reliable long-term reference.

Why not use _rid/selflink?

  • _rid - system-assigned identity in Comsos DB inner storage. It value is stable as long as document does not move in storage but it will change whenever document is recreated in storage.
  • _selflink - system-assigned identity similar to _rid, but in addition to _rid it includes similar resource sub-keys for the Cosmos DB database and collection the document is in. So it is a reference to the document from the account level.

First, most likely _rid/_selflink have the potential to be slightly more performant as they are closer to actual data. Though in 99% of situations it should be negligible.

On the downside, _rid/_selflink will change when you move your documents for whatever reason. E.g.,:

  • backup and restore
  • delete document and recreate this with exactly the same data
  • rename Cosmos DB database/collection (currently achieved by creating new and moving data)
  • recreate collection to get some new feature not applicable to existing collections
  • refactor collections structure by moving document types (for business/performance or security concerns)

Should this happen, you would be in a world of pain to discover and fix all references from within your data documents. Ouch. That's fragile and cumbersome assuming you have lots of documents and non-trivial models.

Also, if you look at Microsoft API clients (e.g., the C# client), then the comfortable path is nowadays is to work with database/collection names and ids. Don't fight it. You'll just make your code uglier and you own life harder than intended.

Using them for temporary ad-hoc identities is ok though.

Why id?

id is user-assigned key to a document with uniqueness guarantee within a partition.

  • It is optimized for retrieval in API and perf-wise = faster to develop, better performance.
  • It can be set to a natural key - human-readable and business-wise meaningful without loading the referenced document. = fewer lookups, less confusion, fewer RU/s.
  • It is part of the user data and will never change when you move your documents around = predictable behavior, fewer bad surprises during disaster recovery.

The only caveat is that, as always with user-given identities, you have to plan a bit to be sure the identity range really is unique enough for your needs. Your app can always set stricter uniqueness properties (though they would not be enforced by Cosmos DB) or if you need ultimate uniqueness, then use Guids.

What about containers?

Same arguments apply to containers/databases.

The id is only unique within the document partition. You could have as many documents with the same id as long as they have a different partition key values.

The _rid is indeed unique and it's the best form of identification for a document. You can achieve the same by using the id and also providing the partition key value if your collection is partitioned.

There are two different types of reading a document directly without querying for it.

  • Using its self link which looks like this dbs/db_resourceid/colls/coll_resourceid/documents/doc_resourceid and uses the _rid values
  • Using its alternative link which looks like this dbs/db_id/colls/coll_id/documents/doc_id which uses the id

The safest form of document identification you can use is the one that uses the _rids.

In both of your questions, you should go with the self link.

Related