Cosmos DB 存储过程:我可以查询数据库,但是当我尝试更新插入时,出现'not same partition'错误



我知道存储过程在单个分区键的作用域中运行。

也可以进行更改数据的操作,而不仅仅是读取数据

ID必须是字符串,所以我必须滚动自己的自动增量器,以便在文档中使用一个单独的属性。

我正在尝试制作一个在单个存储过程中运行的简单的自动递增数字生成器。

我正在模拟文件树对数据进行分区,使用正斜杠来分隔+连接构成分区名称的重要位。像这样:

/sometype/foo/bar/

/sometype/ids/

第一项始终是文档类型,每个文档类型都将有一个"ids"子分区。

/sometype/ids/分区将保留为该文档类型创建的所有数字id,而不是保留文档,用于自动递增。

这满足了分区内的唯一性、存储过程执行范围和文档类型内的唯一文档计数,这对我来说很好。

我在一个存储过程中遇到了麻烦,我想获得一个指定的id,或者在不存在的情况下创建它。

我可以使用存储过程查询分区,但upstart使用相同的分区键抛出错误。

我用";pkey";作为将保存分区键的属性的名称。

这是代码:

//this stored procedure is always called from a partition of type /<sometype>/ids/ , where <sometype> os one of my document types.
//the /sometype/ids/ is a partition to reserve unique numerical ids, as Cosmos DB does not have a numerical increment out of the box, I am creating a facility for that. 
//the actual documents of /sometype/ will be subpartitioned as well for performance. 
function getId(opkey, n, id) {
// gets the requested number if available, or next one.
//opkey: string - a partition key of cosmos db of the object that is going to consume the generated ID, if known. must start with /<sometype>/ which is the same that is being used to call this SP
//n: integer - a numerical number for the autoincrement
//id = '' : string - a uuid of the document that is using this id, if known
if (opkey === undefined) throw new Error('opkey cannot be null. must be a string. must be a valid partition key on Cosmos DB.');
n = (n === undefined || n === null)?0:n;
id = (id === undefined || id === null)?'':id;
var collection = getContext().getCollection();
//make opkey parameter into an array
var split_pkey = opkey.split('/');
//recreate the pkey /<sometype>/ids/ because I can't find a reference to this string inside the context. 
var idpkey = '/'+split_pkey[1]+'/ids/'; 
//first query as SQL
//get highest numerical value.
var q = 'SELECT TOP 1 * FROM c 
WHERE c.pkey = ''+idpkey+'' ORDER BY c.n desc';
//helper function to create uuids. can I ditch it?
function CreateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// Query documents and take 1st item.
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
q
,
function (firstError, feed, options) {
if (firstError) throw "firstError:"+firstError;
//console.log(collection.options.);
console.log(idpkey+', '+n+', '+id+"-");
var maxn = 0;
// take 1st element from feed
if (!feed || !feed.length) {
//var response = getContext().getResponse();
//response.setBody(null);
}
else {
maxn = feed[0].n;
//var response = getContext().getResponse();
//var body = { original: '', document: '', feed: feed[0] };
//response.setBody(JSON.stringify(body));
}
console.log(maxn);
//query for existing numerical value
q = 'SELECT TOP 1 * FROM c 
WHERE c.pkey = ''+idpkey+'' 
AND 
c.number = '+n+' 
OR 
c.id = ''+id+''';
var isAccepted2 = collection.queryDocuments(
collection.getSelfLink(),
q
,
function (secondFetchError, feed2, options2) {
if (secondFetchError) throw "second error:"+secondFetchError;
//if no numerical value found, create a new (autoincrement)
if (!feed || !feed.length) {
console.log("|"+idpkey);
var uuid = CreateUUID();
var newid = {
id:uuid,
pkey:idpkey,
doc_pkey:opkey,
n:maxn+1
};
//here I used the javascript query api
//it throws an error claiming the primary key is different and I don't know why, I am using idpkey all the time
var isAccepted3 = collection.upsertDocument(
collection.getSelfLink(),
newid
,
function (upsertError,feed3,options3){
if (upsertError) throw "upsert error:"+upsertError;
//if (upsertError) console.log("upsert error:|"+idpkey+"|");
//var response = getContext().getResponse();
//response.setBody(feed[0]);
});
if (!isAccepted3) throw new Error('The third query was not accepted by the server.');

console.log(" - "+uuid);

}
else {
//if id found, return it
//maxn = feed[0].n;
var response = getContext().getResponse();
response.setBody(feed[0]);
//var body = { original: '', document: '', feed: feed[0] };
//response.setBody(JSON.stringify(body));
}
});
if (!isAccepted2) throw new Error('The second query was not accepted by the server.');
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');

}

错误消息为:"源自脚本的请求不能引用提交客户端请求的分区键以外的分区键">

我不明白为什么它认为它有错误,因为我在所有查询中都使用变量idpkey来保存正确的pkey。

谈论大脑放屁!我违反了自己的规则,因为我在请求中拼错了分区名称,使分区键/sometype/的第一部分与发送的参数不同,导致执行范围的分区键与idpkey变量不匹配,从而导致错误。

最新更新