Cosmos DB (DocumentDB) Bindings

Retrieve a single document by ID

The Cosmos DB binding can automatically retrieve a document from Cosmos DB and bind it to a parameter. This example uses an object. The Cosmos DB binding uses a binding expression ({id}) to look up a document from Cosmos DB using the id value from the HttpTrigger route.

[FunctionName("CosmosDBSample")]
public static HttpResponseMessage Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "foo/{id}")] HttpRequestMessage req,
    [DocumentDB("test", "test", ConnectionStringSetting = "CosmosDB", Id = "{id}")] object document)
{
    if (document == null)
    {
        return req.CreateResponse(HttpStatusCode.NotFound);
    }
    else
    {
        return req.CreateResponse(HttpStatusCode.OK, document);
    }
}

Retrieve a list of documents

The Cosmos DB binding can automatically retrieve a list of documents from Cosmos DB and bind it to a parameter. The sqlQuery property of the binding is used to specify a query to use to retrieve the documents. This example demonstrates how to select the five most recent documents from the collection as determined by the _ts timestamp property.

[FunctionName("CosmosDBSample")]
public static HttpResponseMessage Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestMessage req,
    [DocumentDB("test", "test", ConnectionStringSetting = "CosmosDB", sqlQuery = "SELECT top 2 * FROM c order by c._ts desc")] IEnumerable<object> documents)
{
    return req.CreateResponse(HttpStatusCode.OK, documents);
}

Save multiple documents to a collection

The IAsyncCollector lets you save multiple documents within one execution of your Function.

using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

public class MyClass
{
    public string id { get; set; }
    public string name { get; set; }
}

[FunctionName("CosmosDbSample")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]MyClass[] classes,
    TraceWriter log,
    [DocumentDB("ToDoList", "Items", ConnectionStringSetting = "CosmosDB")] IAsyncCollector<MyClass> documentsToStore)
{
    log.Info($"Detected {classes.Length} incoming documents");
    foreach (MyClass aClass in classes)
    {
        await documentsToStore.AddAsync(aClass);
    }

    return new HttpResponseMessage(HttpStatusCode.Created);
}

Trigger a Function based on changes in Cosmos DB

You can trigger a Function based on changes in your Cosmos DB collections. In this sample we are sending the changes to a second collection using the IAsyncCollection explained in this other recipe. You could process or work with the documents before sending it to the second collection.

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;

[FunctionName("CosmosDbSample")]
public static async Task Run(
    [CosmosDBTrigger("ToDoList","Items", ConnectionStringSetting = "CosmosDB")] IReadOnlyList<Document> documents,
    TraceWriter log,
    [DocumentDB("ToDoList", "Migration", ConnectionStringSetting = "CosmosDB", CreateIfNotExists = true)] IAsyncCollector<Document> documentsToStore)
{
    foreach (var doc in documents)
    {
        log.Info($"Processing document with Id {doc.Id}");
        // work with the document, process or create a new one
        await documentsToStore.AddAsync(doc);
    }
}

Using DocumentClient

If you have complex queries that are not supported by id and sqlQuery of the Cosmos DB input binding, you can use the DocumentClient directly.

using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;

[FunctionName("CosmosDBSample")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestMessage req, 
    [DocumentDB("test", "test", ConnectionStringSetting = "CosmosDB")] DocumentClient client, 
    int minAge, 
    TraceWriter log)
{
    Uri collectionUri = UriFactory.CreateDocumentCollectionUri("mydb", "mycollection");

    IDocumentQuery<Person> query = client.CreateDocumentQuery<Person>(collectionUri)
        .Where(p => p.Age >= minAge)
        .AsDocumentQuery();

    while (query.HasMoreResults)  
    {
        foreach (Person result in await query.ExecuteNextAsync())
        {
            log.Info(result.Age.ToString());
        }
    }
}

Customize a DocumentClient and reuse it between executions

You can create your own DocumentClient and customize it for your needs, while maintaining a single shared instance for all the Function's executions. The single instance is ensured by the use of the static keyword when declaring the DocumentClient.

using System;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

private static DocumentClient client = GetCustomClient();
private static DocumentClient GetCustomClient()
{
    DocumentClient customClient = new DocumentClient(
        new Uri(ConfigurationManager.AppSettings["CosmosDBAccountEndpoint"]), 
        ConfigurationManager.AppSettings["CosmosDBAccountKey"],
        new ConnectionPolicy
        {
            ConnectionMode = ConnectionMode.Direct,
            ConnectionProtocol = Protocol.Tcp,
            // Customize retry options for Throttled requests
            RetryOptions = new RetryOptions()
            {
                MaxRetryAttemptsOnThrottledRequests = 10,
                MaxRetryWaitTimeInSeconds = 30
            }
        });

    // Customize PreferredLocations
    customClient.ConnectionPolicy.PreferredLocations.Add(LocationNames.CentralUS);
    customClient.ConnectionPolicy.PreferredLocations.Add(LocationNames.NorthEurope);

    return customClient;
}

[FunctionName("CosmosDbSample")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "foo/{id}")] HttpRequestMessage req,
    string id,
    TraceWriter log)
{
    Uri documentUri = UriFactory.CreateDocumentUri("ToDoList", "Items", id);
    Document doc = await client.ReadDocumentAsync(documentUri);

    if (doc == null)
    {
        return req.CreateResponse(HttpStatusCode.NotFound);
    }

    return req.CreateResponse(HttpStatusCode.OK, doc);
}

Takeaways

  • The static keyword acts as a Singleton, maintaining the same instance for all the executions within a Function's instance.
  • You can customize your DocumentClient with your own ConnectionPolicy requirements.

Read more