You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Cosmos DB UpsertDocumentAsync C# API 工作原理及操作疑问

Azure Cosmos DB UpsertDocumentAsync 工作机制及代码执行逻辑详解

Hey there! Let's break down how the UpsertDocumentAsync API works in Azure Cosmos DB, and walk through exactly what's happening in your code snippet.

核心工作原理

First off, "Upsert" is a portmanteau of Update + Insert—and that's exactly what this API does. Here's the server-side logic Cosmos DB follows when you call it:

  • It checks if a document with the same Id and matching partition key (if your container uses partitioning) already exists in the target container.
  • If the document exists: Cosmos DB replaces the entire existing document with the one you sent (this is a full replacement, not a partial update—unless you use patch APIs instead).
  • If the document doesn't exist: Cosmos DB inserts the new document into the container.

A key point: Upsert is an atomic operation handled entirely on the Cosmos DB server. You don't need to read the document first to use it—this avoids race conditions that could happen if you read, modify, and write from the client (like another process updating the document between your read and write).

Let's Walk Through Your Code

First, let's note a small issue in your code: you're redeclaring the upsertOrder variable with var twice, which will throw a compile error. I'll fix that as we go, but let's break down each step:

Your original code (with the duplicate var fixed):

var response = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, "docId"), new RequestOptions { PartitionKey = new PartitionKey("pk") });
var upsertOrder = response.Resource;
upsertOrder = new Measurements { Id = "docId", value = 3243 }; // Removed duplicate var
upsertOrder.SetPropertyValue("value", 5678);
response = await client.UpsertDocumentAsync(collectionUri, upsertOrder, new RequestOptions { PartitionKey = new PartitionKey("pk") });

Step 1: Reading the Existing Document

You call ReadDocumentAsync to fetch the document with Id = "docId" from the partition "pk". This pulls the current state of the document from Cosmos DB into response.Resource, which you assign to upsertOrder.

Step 2: Overwriting the Read Document

Here's the critical part: you immediately create a brand new Measurements object with the same Id and assign it to upsertOrder. This completely discards the document you just read—so that initial ReadDocumentAsync call doesn't actually affect the final Upsert operation at all.

Step 3: Modifying the New Object

You use SetPropertyValue("value", 5678) to update the value field of your new Measurements object. A quick note: if Measurements is your own POCO (Plain Old CLR Object) class, you could just do upsertOrder.value = 5678 instead of using SetPropertyValue—that method is more commonly used with the dynamic Document type from the Cosmos DB SDK.

Step 4: Executing the Upsert

When you call UpsertDocumentAsync, Cosmos DB checks the container for a document with Id = "docId" in partition "pk":

  • If that document exists: Cosmos DB replaces the entire existing document with your new Measurements object (all fields will be overwritten to match the new object, not just the value field).
  • If it doesn't exist: Cosmos DB inserts your new Measurements document into the partition "pk".

What If You Wanted to Update the Existing Document?

If your goal was to modify the existing document (instead of creating a new one from scratch), you should skip creating a new Measurements object and modify the one you read:

var response = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, "docId"), new RequestOptions { PartitionKey = new PartitionKey("pk") });
// Convert the read resource to your POCO type
var upsertOrder = (Measurements)response.Resource;
// Modify the existing object's properties
upsertOrder.value = 5678;
// Upsert the updated object
response = await client.UpsertDocumentAsync(collectionUri, upsertOrder, new RequestOptions { PartitionKey = new PartitionKey("pk") });

This way, you're preserving the existing fields of the document and only updating the value field (or whatever fields you need).

Key Additional Notes

  • Partition Key Matching: Always make sure the partition key you specify in the RequestOptions matches the partition key value of the document. If they don't, Cosmos DB won't find the existing document and will insert a new one—resulting in duplicate documents with the same Id but different partition keys (since Cosmos DB's uniqueness is based on Id + Partition Key).
  • Performance: If you don't need the existing document's data, skip the ReadDocumentAsync call entirely. Directly construct your object and call UpsertDocumentAsync—this saves a network round trip and improves performance.
  • Atomicity: As mentioned earlier, Upsert is atomic. Cosmos DB guarantees that either the update or insert completes successfully—no partial writes or inconsistent states.

内容的提问来源于stack exchange,提问作者toto'

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:52:13