IDocumentClient.UpsertDocumentAsync不会更新,它会插入重复的ID

时间:2018-02-13 21:42:09

标签: c# azure azure-cosmosdb upsert

我在C#中有一个VS2017解决方案,我正在使用 IDocumentClient.UpsertDocumentAsync 将一些文档插入到我的cosmosdb documentdb集合中。但是我注意到它实际上创建了具有相同id的新文档,而集合中已经有一个带有该id的文档。

现在,在插入具有相同ID的新文档后,查询结果如下所示:

select * from c where c.id = "aaaa-bbbb-cccc"

[
    {
        "id": "aaaa-bbbb-cccc",
        "firstname": "john",
        "lastname": "doe"
    },
    {
        "id": "aaaa-bbbb-cccc",
        "firstname": "john",
        "lastname": "doe",
        "age": "35"
    }
]

我对这种行为很困惑;也许我没有正确理解“upsert”的定义。如果有人能为我澄清这一点,我将不胜感激。

2 个答案:

答案 0 :(得分:5)

在Cosmos DB中,“id”不是唯一值。相反,它是分区键(在您的情况下为“age”)和“id”的组合,它是唯一的。 Cosmos DB允许分区键不存在(因为它对模式很宽松)并将缺少的分区键值视为特殊值(=“undefined”)。分区键值也是不可变的 - 要更改这些值,您需要删除/插入。

因此,在这种情况下,您有两个文档,一个带有[age="35", "aaaa-bbbb-cccc"],另一个带有[age=undefined, "aaaa-bbbb-cccc"],由upsert调用创建。如果您将upsert调用更改为replace,则会收到NotFound错误。

答案 1 :(得分:3)

  

我对这种行为很困惑;也许我不合适   理解" upsert"的定义。

Azure Cosmos DB中的

Upsert操作将创建一个文档,如果它尚未存在,否则将覆盖它。 “Should I use a Create or a Replace operation?”,数据库为您做出此决定。这样可以节省额外的请求单位费用,并且由于操作是原子操作,因此可以消除竞争条件的可能性。

然而,cosmos db只确保每id partition key的唯一性。

<强> 样品:

[
  {
    "id": "1",
    "name": "jay1"
  },
  {
    "id": "1",
    "name": "jay2"
  },
  {
     "id": "1"
  }
]

分区键是name。分区键用于分片,它充当数据的逻辑分区,并为Cosmos DB提供跨分区分布数据的自然边界。以上3个文档具有不同的分区:"jay1""jay2"None,因此id属性在其自己的逻辑分区中是唯一的。现在,如果您使用Upsert方法将具有相同id的文档添加到其各自的分区,则将覆盖以前的文档。

您可以参考文档:Unique keys in Azure Cosmos DBPartition and scale in Azure Cosmos DB