Writing Azure Cosmos DB Data from Azure Functions

This is the third part in a series of articles.

In part 2 of this series we saw how to read data from Cosmos DB, in this article we’ll see how to write data to Cosmos DB from an Azure Function.

As with input, output is achieved by the use of the [CosmosDB] binding attribute and as before, the database name, collection name, id, partition, and connection string can be defined.

In part 2 we saw how to use binding expressions to take data from the HTTP querystring and use that to select a document to read in (e.g. by Id). In this article we’ll see how we can do a similar thing when the trigger type is for a storage queue.

The following function is triggered when a message is written to the “update-pizza-driver-location” queue:

[FunctionName("UpdatePizzaDriverLocation")]
[return: CosmosDB(databaseName: "pizza", collectionName: "driver", ConnectionStringSetting = "pizzaConnection", Id = "{Id}", PartitionKey = "{StoreId}")]
public static Driver Run(
    [QueueTrigger("update-pizza-driver-location")] PizzaDriverLocationUpdate locationUpdate,
    [CosmosDB(databaseName: "pizza", collectionName: "driver", ConnectionStringSetting = "pizzaConnection", Id = "{Id}", PartitionKey = "{StoreId}")] Driver driver,            
    ILogger log)
{
    if (driver is null)
    {
        log.LogError($"Driver Id/partition {locationUpdate.Id}/{locationUpdate.StoreId} not found in database.");
        return null;
    }

    driver.Latitude = locationUpdate.NewLat;
    driver.Longitude = locationUpdate.NewLong;

    return driver;
}

The first thing to notice in the preceding function that there are 2 instances of the [CosmosDB] binding attribute, one as the return binding for the method (the output binding to perform the update) and the input binding in the Run method parameter (the input binding to read the current state of the Driver).

Another thing to notice is the use of the {Id} and {StoreId} binding expressions. These expressions assume that the incoming queue message contains JSON properties that match these expressions, for example:

{
    "Id" : "1",
    "StoreId" : "101",
    "NewLat" : 111.2,
    "NewLong" : 3110.3
}

The Driver and PizzaDriverLocationUpdate classes look like the following:

public class PizzaDriverLocationUpdate
{
    public string Id { get; set; }
    public string StoreId { get; set; }
    public double NewLat { get; set; }
    public double NewLong { get; set; }
}

 

public class Driver
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }
    public string StoreId { get; set; }
    public string Name { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

Note in the Driver class, the [JsonProperty(PropertyName = "id")] attribute is mapping Id to id in Cosmos DB.

If you want to write multiple documents from a single function invocation you make use of an IAsyncCollector, for example IAsyncCollector<Driver> drivers and then use drivers.AddAsync(newDriver) method to write multiple documents.

In the next part of this series we’ll see how we can combine Azure Cosmos DB triggers with SignalR to create notifications to clients when data changes.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

Comments (3) -

  • Roy Molenaar

    4/15/2020 6:47:26 AM | Reply

    Hi Jason, This is exactly what i need.
    But so far i cant build my solution, because of my setup i think. I have metadata generation failed, cant find system runtime etc.
    Do you might have the github sample for me please? And what are the prerequitsites? sdk, etc

    Cheers Roy Molenaar

    • Jason Roberts

      4/15/2020 7:07:52 AM | Reply

      Hi Roy, sorry I don't think I have this on GitHub

  • rocio

    5/24/2020 6:21:49 PM | Reply

    Hi Jason, I follow your instructions and works ok with 1 document. Then I try to update multiple documents and I've got this
    foreach statement cannot operate on variables of type "IAsyncCollector<Driver>" because  "IAsyncCollector<Driver>" does not contain a public definition for 'GetEnumerator'

    What's wrong with that. I'm new with this in Azure and functions. Please be gentle with me.

Add comment

Loading