0
votes

I have an azure function taking in messages from an Azure service bus queue and sending documents to cosmosDB. I'm using Azure functions 1.x:

public static class Function1
{
    [FunctionName("Function1")]
    public static void Run([ServiceBusTrigger("ServiceBusQueue", AccessRights.Manage, Connection = "ServiceBusQueueConnection")]BrokeredMessage current, [DocumentDB(
            databaseName: "DBname",
            collectionName: "Colname",
            ConnectionStringSetting = "CosmosDBConnection")]out dynamic document, TraceWriter log)
    {
        document = current.GetBody<MyObject>(); 
        log.Info($"C# ServiceBus queue triggered function processed the message and sent to cosmos"); 
    }
}

This inserts to cosmos successfully, but when updating I get errors:

Microsoft.Azure.Documents.DocumentClintException: Entity with the specified id already exists in the system.

They key I'm trying to update on is the partition key of that collection.

I saw this question: Azure function C#: Create or replace document in cosmos db on HTTP request But It seems like my usage is similar to the one in Matias Quarantas answer. Also he mentioned that using an out parameter causes an upsert on cosmos.

How can I create this "upsert" function, while still using azure function 1.x?

1
Functions V1 also does an upsert. Is your collection partitioned?Matias Quaranta

1 Answers

1
votes

The binding does indeed do an Upsert operation.

I created this sample Function that takes an Http payload (JSON) and stores it in Cosmos DB as-is:

[FunctionName("Function1")]
public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req,
   [DocumentDB("MyDb", "MyCollection", ConnectionStringSetting = "MyCosmosConnectionString")] out dynamic document,
   TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");

    dynamic data = req.Content.ReadAsAsync<object>().GetAwaiter().GetResult();
    document = data;

    return req.CreateResponse(HttpStatusCode.OK);
}

If I send a JSON payload to the Http endpoint, the output binding works as expected:

Sending payload with Postman

When I check the Data Explorer, I see:

Document in the Data Explorer

If I send a second payload, this time, adding a property (same id):

Sending updated payload through Postman

The Data Explorer shows the document was updated, with the same Function code:

Document updated in Data Explorer

Can you add the full Exception/Error trace? Is your Service Bus Message including an "id"? Is your collection partitioned?

If your collection is partitioned and you are changing the value of the Partition key property, then the binding won't update the existing document, it will create a new one because the Upsert operation won't find an existing document (based on the id/partition key). But it won't throw an exception.