Azure 用于更新或插入属于多个分区键的文档的存储过程
我有一个属于分区集合的文档列表。我想我可以使用存储过程来完成这项工作,而不是从.NET客户端查询每个文档并进行更新或插入 我最初没有意识到的是,存储过程是在单个分区键的事务范围内执行的。因此,我得到了必须为此操作提供的分区键值 问题是文档(我正试图插入)可能属于不同的分区。如何在存储过程中实现这一点?在我的例子中,SP是无用的,除非它可以在多个分区上运行 这就是我构建SP的方式:Azure 用于更新或插入属于多个分区键的文档的存储过程,azure,azure-cosmosdb,Azure,Azure Cosmosdb,我有一个属于分区集合的文档列表。我想我可以使用存储过程来完成这项工作,而不是从.NET客户端查询每个文档并进行更新或插入 我最初没有意识到的是,存储过程是在单个分区键的事务范围内执行的。因此,我得到了必须为此操作提供的分区键值 问题是文档(我正试图插入)可能属于不同的分区。如何在存储过程中实现这一点?在我的例子中,SP是无用的,除非它可以在多个分区上运行 这就是我构建SP的方式: function upsertEcertAssignments(ecerts) { var collecti
function upsertEcertAssignments(ecerts) {
var collection = getContext().getCollection();
var collectionLink = collection.getSelfLink();
var response = getContext().getResponse();
// Validate input
if (!ecerts) throw new Error("The ecerts is null or undefined");
if (ecerts.length == 0) throw new Error("The ecerts list size is 0");
// Recursively call the 'process' function
processEcerts(ecerts, 0);
function processEcerts(ecerts, index) {
if (index >= ecerts.length) {
response.setBody(index);
return;
}
var query = {query: "SELECT * FROM DigitalEcerts c WHERE c.code = @code AND c.collectionType = @type", parameters: [{name: "@code", value: ecerts[index].code}, {name: "@type", value: 0}]};
var isQueryAccepted = collection.queryDocuments(collectionLink, query, {partitionKey: ecerts[index].code}, function(err, foundDocuments, foundOptions) {
if (err) throw err;
if (foundDocuments.length > 0) {
var existingEcert = foundDocuments[0];
ecerts[index].id = existingEcert.id;
var isAccepted = __.replaceDocument(existingEcert._self, ecerts[index], function(err, updatedEcert, replacedOptions) {
if (err) throw err;
processEcerts(ecerts, index + 1);
});
if (!isAccepted) {
response.setBody(index);
}
} else {
var isAccepted = __.createDocument(__.getSelfLink(), ecerts[index], function(err, insertedEcert, insertedOptions) {
if (err) throw err;
processEcerts(ecerts, index + 1);
});
if (!isAccepted) {
response.setBody(index);
}
}
});
if (!isQueryAccepted)
response.setBody(index);
}
}
从.NET中,如果我这样称呼它,我会遇到partitionKey值问题:
var continuationIndex = await _docDbClient.ExecuteStoredProcedureAsync<int>(UriFactory.CreateStoredProcedureUri(_docDbDatabaseName, _docDbDigitalEcertsCollectionName, "UpsertDigitalMembershipEcertAssignments"), digitalEcerts);
var continuationIndex=wait _docDbClient.ExecuteStoredProcedureAsync(UriFactory.CreateStoredProcedureUri(_docDbDatabaseName,_docDbDigitalEcertsCollectionName,“UpsertDigitalMembershipRecertAssignments”),digitalEcerts);
如果我用分区键调用它,它会工作…但它是无用的:
var continuationIndex = await _docDbClient.ExecuteStoredProcedureAsync<int>(UriFactory.CreateStoredProcedureUri(_docDbDatabaseName, _docDbDigitalEcertsCollectionName, "UpsertDigitalMembershipEcertAssignments"), new RequestOptions { PartitionKey = new PartitionKey(digitalEcerts[0].Code) }, digitalEcerts.Take(1).ToList());
var continuationIndex=await\u docDbClient.ExecuteStoredProcedureAsync(UriFactory.CreateStoredProcedureUri(\u docDbDatabaseName,\u docDbDigitalEcertsCollectionName,“UpsertDigitalMembershipRecertAssignments”),新请求选项{PartitionKey=new PartitionKey(digitalEcerts[0].code)},digitalEcerts.Take(1).ToList();
我感谢你的指点
谢谢
如果针对存储过程注册的集合是
单分区集合,则事务的作用域为所有
集合中的文档。如果集合已分区,
然后,存储过程在
单分区密钥。然后必须执行每个存储过程
包括与作用域对应的分区键值
事务必须在以下条件下运行
你可以参考上面提到的描述。我们可以通过在FeedOptions
参数中将EnableCrossPartitionQuery
设置为true
来跨分区查询文档。但是,RequestOptions
对于执行存储过程没有这样的属性
所以,在执行sp时,似乎必须提供分区键。当然,它可以被upsert函数替换。从业务逻辑的角度来看,这是无用的,但是如果批量操作,SP可以释放一些性能压力,因为SP在服务器端运行
希望它能帮助您。听上去,您的唯一id是
code
和类型的组合。我建议将您的id
属性设置为两者的组合
这保证了您的id
是唯一的,但也消除了查询它的需要。真正的问题是,为什么使用存储过程而不是SDK提供的Upsert方法?这是因为我需要文档id
来执行Upsert!除非我完全错了,id
是Cosmos知道文档是相同的。我所拥有的文档不是从Cosmos数据库中提取的……但是它们具有相同的属性。因此,我最终使用PK和type查询每个文档。如果该文档存在,我将使用该id向上插入。这需要很长时间,尤其是我有大约100个文档需要部分更新..id在CosmosDB中不是唯一的属性。它只有在自己的分区内才是唯一的。好的…谢谢你…但我不确定我是否理解。假设有一个实体具有以下3个属性:id=''、code='123'和type=0。id
未知。如果我执行upsert
,它将始终插入文档,因为id
与任何现有文档都不匹配…对吗?除非我首先使用code
和type
进行查询,否则我无法知道如何更新或插入。这是我的问题。我希望我可以使用SP在服务器上执行查询并替换或插入,以避免往返。查询和键入是否足以为您提供唯一的id
?如果是,那么为什么不将id
设置为code
和type
的组合?是的……谢谢……这是我在问题中提到的文档。实际上,我很惊讶为服务器端提供的所有示例代码都使用未分区的集合?这是不现实的Upsert
对我不起作用…我必须首先查询以找到id
…这是因为源文档不是从Cosmos中提取的…因此它们的id
未知。虽然这解决了我的问题,但它当然不能解决我在存储过程中遇到的问题。