Tuesday, 6 December 2016

Find docs with no PartitionKey in Azure DocumentDb

When you are using Partitioned Collections in Azure DocumentDb you need to specify a Partition Key on each Document. At least, I thought you did. But, it turns out that you actually can save documents without a partitionkey. But if you do, you'll have a hard time retrieving or deleting them - until you meet Undefined.Value.
Note: This post is written for C#, I am not sure about the equivalent for other languages.


Details

If you create a Partitioned Collection in Azure DocumentDb you probably think that every document you save must have a partitionkey property and probably also that it must have a value. In this post I am dealing with the situation where you don't have a partition key property on your document at all, not the situation where you have one but you set it to null or an empty string.

For example, if you have created your collection with code similar to this;
var docCollection = new DocumentCollection()
{
   Id = this.collectionName
};
docCollection.PartitionKey.Paths.Add("/partitionKey");
await docClient.CreateDocumentCollectionAsync(
                    UriFactory.CreateDatabaseUri(this.dbName), 
                    docCollection);
and you then try to save an instance of a class that looks like this:
public class MyItem
{
    [JsonProperty("id")]
    public string Id { get; set; }

    public string SomeValue { get; set; }
}
then you may expect to get an error. But, in fact, it will save just fine as I found out to my detriment after a major refactoring.

Now that you have that item in the database you will find it hard to retrieve it and even harder to delete it - until you meet your new friend Undefined.Value.

How to read the document:

MyItem item = (dynamic)client.ReadDocumentAsync(
                           UriFactory.CreateDocumentUri(DbName, CollectionName, id),
                           new RequestOptions() {
                             PartitionKey = new PartitionKey(Undefined.Value)
                           })
                         .Result.Resource;

How to delete the document:

client.DeleteDocumentAsync(
          UriFactory.CreateDocumentUri(DbName, CollectionName, id), 
          new RequestOptions() { PartitionKey = new PartitionKey(Undefined.Value) });
Many thanks to Aravind Ramachandran for telling me about Undefined.Value.





3 comments:

  1. Thanks for your article. I found it extremely helpful and used it as the basis for writing some logic to purge records without a partition key (blogged here: http://www.codecadwallader.com/2016/12/31/purging-azure-documentdb-records-without-a-partitionkey/ ).

    I referenced people back to this article for finding the records in the first place. Thanks again!

    ReplyDelete
    Replies
    1. Excellent post :)
      Funnily enough, I wanted to write that code too but never got around to it, thanks for doing it and sharing it.

      Delete
  2. Extremely helpful post!! Thanks a bunch!

    ReplyDelete