4
votes

I'm trying to build an Azure function in C# that creates a new document object in Azure cosmos DB using SQL API if an id doesn't already exist and updates a document object if it already exists.

The context behind this is logging chatbot conversation history to unique user sessions.

Input:
HTTP GET Request with parameters (id (string), chatHistory(string) and chatDateTime(string))

Output:
If document object with same id already exists - then update document with input chatHisotry and chatDateTime.

If no document object exists with same id then create a new document object with id, chatHistory and chatDateTime equal to input.

Any help much appreciated! Been struggling with this one for days.

Example of document object:

{
    "id": "ESCRfAKwlTbH8W5aVRLxgA",
    "chatHistory": "Hi, Hello",
    "chatDateTime": "Fri Sep 21 2018 05:34:35 GMT+0000 (Coordinated Universal Time)",
    "_rid": "RwYSAIqaSVg2AAAAAAAAAA==",
    "_self": "dbs/RwYSAA==/colls/RwYSAIqaSVg=/docs/RwYSAIqaSVg2AAAAAAAAAA==/",
    "_etag": "\"00007400-0000-0000-0000-5ba482ed0000\"",
    "_attachments": "attachments/",
    "_ts": 1537508077
}
2
You are developing this in direct azure portal or in Visual Studio.?SH7
Can you know us what you've done until now? What you've tries and what you're struggling with?Nick Chapsas
Hi! I'm developing this on the direct Azure portal.Michael
@NickChapsas I've been messing around with this below (random tutorial I've found online) which lets me insert documents into cosmos document db. github.com/MicrosoftDocs/azure-docs/blob/master/articles/… but no luck building conditional logic into itMichael
@NickChapsas I've managed to build a function that inputs data into the cosmos document db upon http get request however I'm struggling to make the function replace/upsert(?) data if the document object already existsMichael

2 Answers

7
votes

You can use the Azure Functions' Cosmos DB Output Binding. The Output binding does an Upsert operation.

[FunctionName("HttpTriggerWithSingleDocument")]
    public static async Task<HttpResponseMessage> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
        [DocumentDB(databaseName: "your-db",
            collectionName: "your-collection",
            ConnectionStringSetting = "CosmosDBConnectionString")] out dynamic documentToSave)
    {
        dynamic data = await req.Content.ReadAsAsync<object>();

        if (data == null)
        {
            documentToSave = null;
            return req.CreateResponse(HttpStatusCode.BadRequest);
        }

        documentToSave = data;

        return req.CreateResponse(HttpStatusCode.Created);
}

Azure Portal version:

using System.Net;

public static async Task<HttpResponseMessage> Run(
            HttpRequestMessage req,
            IAsyncCollector<dynamic> documentsToStore)
        {
            dynamic data = await req.Content.ReadAsAsync<object>();

            if (data == null)
            {
                return req.CreateResponse(HttpStatusCode.BadRequest);
            }

            await documentsToStore.AddAsync(data);

            return req.CreateResponse(HttpStatusCode.Created);
    }

And you also need the function.json updated to something like:

{
  "bindings": [
    {
      "name": "req",
      "type": "httpTrigger",
      "direction": "in"
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    },
    {
      "type": "documentDB",
      "name": "documentsToStore",
      "databaseName": "<your-database-name>",
      "collectionName": "<your-collection-name>",
      "createIfNotExists": false,
      "connection": "<your-connection-setting-name>",
      "direction": "out"
    }
  ]
}

More samples available here: https://github.com/ealsur/serverless-recipes/tree/master/cosmosdboutputbindings

-1
votes

Here is an example how to do it. You just need to adjust it to you needs.

    [FunctionName("Function1")]
    public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
    TraceWriter log)
    {
        dynamic data = await req.Content.ReadAsAsync<object>();

        var connectionString = "DbUri";
        var key = "DbKey";

        using (var client = new DocumentClient(new Uri(connectionString), key))
        {
            var collectionLink = UriFactory.CreateDocumentCollectionUri("DbName", "CollectionName");
            await client.UpsertDocumentAsync(collectionLink, data);
        }

        return req.CreateResponse(HttpStatusCode.OK);
    }