首页 文章

用于更新或插入属于多个分区键的文档的存储过程

提问于
浏览
0

我有一个属于分区集合的文档列表 . 不是从.NET客户端查询每个文档,而是更新或插入,我想我可以使用存储过程来完成此任务 .

我最初没有意识到存储过程是在单个分区键的事务范围内执行的 . 所以我得到 PartitionKey value must be supplied for this operation .

问题是文件(我试图插入)可能属于不同的分区 . 如何在存储过程中完成此操作?就我而言,SP是无用的,除非它可以在多个分区上运行 .

这就是我构建SP的方式:

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 = await _docDbClient.ExecuteStoredProcedureAsync<int>(UriFactory.CreateStoredProcedureUri(_docDbDatabaseName, _docDbDigitalEcertsCollectionName, "UpsertDigitalMembershipEcertAssignments"), new RequestOptions { PartitionKey = new PartitionKey(digitalEcerts[0].Code) }, digitalEcerts.Take(1).ToList());

我很欣赏任何指针 .

谢谢 .

2 回答

  • 1

    根据它的声音,您的唯一ID是 codetype 的组合 . 我建议你将 id 属性作为两者的组合 .

    这可以保证 id 是唯一的,但也无需查询它 .

  • 0

    如果注册存储过程的集合是单分区集合,则事务的范围限定为集合中的所有文档 . 如果集合是分区的,则存储过程在单个分区键的事务范围内执行 . 然后,每个存储过程执行必须包括与事务必须在其下运行的范围相对应的分区键值 .

    你可以参考上面提到here的描述 . 我们可以通过在 FeedOptions 参数中将 EnableCrossPartitionQuery 设置为 true 来查询文档跨分区 . 但是, RequestOptions 没有执行存储过程的此类属性 .

    所以,执行sp时似乎必须提供分区键 . 当然,它可以用upsert函数代替 . 从业务逻辑的角度来看它是无用的,但是如果是批量操作,SP可以释放一些性能压力,因为SP在服务器端运行 .

    希望它能帮到你 .

相关问题