Skip to main content Explore View all products (200+) Microsoft Foundry Azure Copilot GitHub Copilot Azure Kubernetes Service (AKS) Azure Cosmos DB Azure Database for PostgreSQL Azure Arc Microsoft Fabric Linux virtual machines in Azure Foundry Models Foundry Agent Service Foundry IQ Foundry Tools Foundry Control Plane Observability in Foundry Control Plane Azure OpenAI in Foundry Models Azure Speech in Foundry Tools Azure Machine Learning View all databases Azure Cosmos DB Azure DocumentDB Azure SQL Azure Database for PostgreSQL Azure Managed Redis Microsoft Fabric Azure Databricks Linux virtual machines in Azure Windows Server on Azure Azure Functions Azure Virtual Machine Scale Sets Azure API Management Azure Container Apps Azure Kubernetes Service (AKS) Azure Kubernetes Fleet Manager Azure Container Registry Azure Red Hat OpenShift Azure Container Instances Azure Container Storage Azure Arc Azure Local Microsoft Defender for Cloud Azure Monitor Microsoft Sentinel Azure Migrate View all solutions (40+) Cloud solutions for small and medium businesses Cloud migration and modernization center Data analytics for AI Azure Databases AI apps and agents Microsoft Marketplace Microsoft Sovereign Cloud AI apps and agents Responsible AI with Azure AI Infrastructure Data analytics for AI Machine learning operations (MLOps) Low-code application development on Azure Integration Services Serverless computing DevOps Migration and modernization center .NET apps migration Databases on Azure Linux on Azure Oracle on Azure SAP on the Microsoft Cloud Adaptive cloud High-performance computing (HPC) Infrastructure as a service (IaaS) Resiliency Azure Essentials Frontier Accelerate for Azure FinOps on Azure Microsoft Marketplace Azure pricing overview Create an Azure account Free Azure services Flexible purchase options Pricing calculator FinOps on Azure Maximize ROI from AI Azure savings plans Azure reservations Azure Hybrid Benefit Virtual Machines Azure SQL Microsoft Foundry Microsoft Fabric Azure Kubernetes Service (AKS) Microsoft Defender for Cloud View more Software Development Companies Microsoft Marketplace Find a partner Resources for Azure partners Get started with Azure Customer stories Analyst reports, white papers, and e-books Videos Learn more about cloud computing Documentation Explore Azure portal Developer resources Quickstart templates Resources for startups Developer community Students Azure for partners Blog Events and Webinars Learn Support Contact Sales Get started with Azure Sign in

When thinking about persisting a JSON document to DocumentDB today you have to stop and ask yourself this question; “Should I do a Create, or should I do a Replace operation?”

If you do a Create operation and the record already exists you will get an error. Similarly, if you do a Replace operation and the record doesn’t exist you will get an error. So the only way to know the answer to this question is to first do a Read or Query by id operation to look for the document, then decide whether to Create or Replace.

A typical implementation might look like this:

using (DocumentClient client = new DocumentClient(new Uri(endpoint), authKey))
{
    var docSpec = new { id = "document id", foo = "bar" };

    var docExists = client.CreateDocumentQuery(UriFactory.CreateCollectionUri(databaseId, collectionId))
                        .Where(doc => doc.Id == "document id")
                        .Select(doc => doc.Id)
                        .AsEnumerable()
                        .Any();

    //doc exists, so replace with the docSpec
    if (docExists)
    {
        Uri docUri = UriFactory.CreateDocumentUri(databaseId, collectionId, "document id");
        await client.ReplaceDocumentAsync(docUri, docSpec);
    }
    //doc does not exist, so create a new document using docSpec
    else
    {
        Uri collUri = UriFactory.CreateCollectionUri(databaseId, collectionId);
        await client.CreateDocumentAsync(collUri, docSpec);
    }
}

This works, most of the time, but is not without problems. The first issue is it costs you additional request units to always ask the database if the record exists first.

Even if you ignore the cost of the additional queries and network round-trips, this code is still a two-step process. There is also still a risk of encountering a race condition. Imagine the scenario where two processes ask the exact same question at the same time; SELECT * FROM c WHERE id = ‘document id’ and both processes get an answer of zero results. Now both processes will proceed to do a Create operation. One process is going to succeed and the other will fail because it tried to insert a record that was already inserted by the other process that won the race.

Today, DocumentDB is happy to announce the addition of support for atomic Upsert operation on the back-end.

Upsert solves these two challenges. With Upsert you don’t need to first ask whether or not the document exists, then decide which operation to perform. The database now makes this decision for you. This not only saves you the additional request unit charges but, because the operation is atomic, it also removes the possibility of a race condition.

Upsert will use the id property of the document and decide whether to create a new document or replace an existing document. It is important to note that DocumentDB does not support partial updates to documents yet. It currently only supports full replacement of documents. Therefore, when a document already exists (matched on id) the full document will be replaced by the contents of the Upsert request.

With Upsert, the code above changes to this:

await client.UpsertDocumentAsync(UriFactory.CreateCollectionUri(databaseId, collectionId), docSpec);

Looking at REST requests under the covers, the above code translates in to a POST on a document resource with a new custom HTTP header x-ms-documentdb-is-upsert set to True. The response from DocumentDB will tell you whether a Create or a Replace was done. If a Create happened, the HTTP response will be StatusCode 201. If a Replace occurred the StatusCode will be a 200.

graphical user interface, text, application, email

In addition to making Upsert requests through client-side requests as shown above, you can also make use of the functionality with the JavaScript server-side SDK when building stored procedures and triggers.

To make use of the Upsert feature you need to download the latest .NETNode.jsPython, or Java SDK based on whichever platform you use.

As with all new features releases, we would love to receive your feedback. Feel free to leave comments below and if you need any help, or have questions, please reach out to us on the developer forums on MSDN or StackovOverflow.

Stay up-to-date on the latest DocumentDB news and features by following us on Twitter @DocumentDB.

Happy document upserting!

 

 

WE ARE MICROSOFT

Explore Microsoft Foundry

The future of AI starts here. Envision your next great AI app with the latest technologies. Get started with Azure.