The API methods for creating databases and collections is easy to find, but how do you get a database and collection that’s already created? It’s definitely the more common use case, but it’s so obviously not there. Never fear, for we can wrap the queries used to get databases and collections in extension methods and pretend that it was always part of the API.
Did you say queries?
Yes, I did. You have to query the system database collection to get a link (not a URI, more like an ID) for your database, and ditto for your collection. The good news is that you don’t actually have to know where those collections live, because there are built in methods for querying them. It was almost easy.
First, get the Database
It’s kind of a two step process. Before you can get a collection, you have to get the database that contains that collection. But we’re going to make it easy with two simple extension methods. The first one will be used to get a Database object. You’ll rarely use this method directly, because the most common reason to get a Database object is to query it for the collection you need.
public static async Task<Database> GetOrCreateDatabaseAsync(
this DocumentClient client, string databaseId)
{
var databases = client.CreateDatabaseQuery()
.Where(db => db.Id == databaseId).ToArray();
if (databases.Any())
{
return databases.First();
}
return await client.CreateDatabaseAsync(
new Database {Id = databaseId});
}
The method first tries to get the Database from the query. If it’s not found, then it creates the Database and returns it. I put the extension on DocumentClient because that is where CreateDatabaseAsync lives, so it made sense that the Get method would be, or appear to be, in the same place.
Then, get the collection
Now that we have a Database object, we can use its SelfLink to get the DocumentCollection. This extension method will be used a lot. It looks like this:
public static async Task<DocumentCollection>
GetOrCreateDocumentCollectionAsync(
this DocumentClient client,
string databaseId,
string collectionId)
{
var database = await GetOrCreateDatabaseAsync(
client, databaseId);
var collections = client
.CreateDocumentCollectionQuery(database.SelfLink)
.Where(col => col.Id == collectionId).ToArray();
if (collections.Any())
{
return collections.First();
}
return await client.CreateDocumentCollectionAsync(
database.SelfLink,
new DocumentCollection {Id = collectionId});
}
This works a lot like the other method, where it tries to get the collection and if it doesn’t exist then it creates the DocumentCollection and returns it. It also uses the other method to get the Database for its SelfLink. Note that this method asks for the database Id, not the object. I did that to make the two step process only look like one step from the outside.
Okay, now what?
This part’s easy. When you need a DocumentCollection object, just use the extension method. You’ll probably want to only do that once and store it in a static. We’re not going to put state in the DocumentCollection object, we really just want the DocumentLink. Here’s how you get it:
private const string DatabaseId = "ContentDB";
private const string CollectionId = "ContentCollection";
private static readonly DocumentCollection Collection =
Client.GetDocumentCollection(DatabaseId, CollectionId).Result;
And then you use it for a document query like so:
public List<Content> GetList()
{
var documentsLink = Collection.DocumentsLink;
var contentList = _client
.CreateDocumentQuery<Content>(documentsLink)
.AsEnumerable().ToList();
return contentList;
}
And that’s it, a very natural way to get the DocumentLink. Then again, maybe it makes sense to just store the DocumentLink as a static and just use that…
Consider that homework.
Pingback: Creating a DocumentDB Repository Layer (Part 1 – Reading) | Bill DeLude