Documentdb存储proc跨分区查询

时间:2016-11-23 12:18:19

标签: c# azure-cosmosdb

我有一个存储过程,它给我一个文档计数(count.js on github)。我已经分区了我的收藏。因此,我现在必须传递分区键作为运行存储过程的选项。

可以以及如何在存储过程中启用跨分区查询(即collection(EnableCrossPartitionQuery = true)),以便我不必指定分区键?

2 个答案:

答案 0 :(得分:2)

无法在DocumentDB中执行扇出存储过程。针对单个分区运行。在尝试切换到分区集合时我遇到了这种困境,不得不进行一些调整。以下是一些选项:

  1. 为每条记录下载1,并将它们计入客户端

  2. 为每个唯一的分区键重新运行存储过程。在我的情况下,这并没有它听起来那么糟糕,因为分区键是一个tenantID,我只有十几个,只期望最多几百个。

  3. 我不确定这个,因为我没有尝试使用分区集合,但现在每个查询都返回x-ms-resource-usage标头中集合的资源使用情况。该标头有一个documentsSize子标头。您可以使用除以文档平均大小的值来获得近似计数。到目前为止,该标题信息中甚至可能存在计数记录。

  4. 此外,还有一个x-ms-item-count标头,但我不确定它是如何表现的。如果您对整个分区集合中的所有记录发送查询并将max-item-count设置为1,那么您将只返回一条记录,并且它不应该花费您很多RU,但我不会知道那个标题是如何表现的。在这种情况下它会返回1吗?或者如果您打扰请求每个页面,它是否返回查询的所有页面最终将返回的文档总数。快速实验应该证实这一点。

答案 1 :(得分:0)

下面您可以找到一些示例代码,这些代码应允许您跨分区读取所有记录。神奇之处在于doForAll函数内部,您可以在顶部看到其调用方式。

// SAMPLE STORED PROCEDURE
function sample(prefix) {

    var share = { counter: 0, hasEntityName : 0, isXXX: 0, partitions: {}, prefix };

    doForAll({
        filter: function limiter(record){
            if (record && record.entityName === 'XXX') return true;
            else return false;
        },
        callback: function handleRecord(record) {
            //Keep track of this partition...
            let partitionKey = record.partitionKey;
            if (share.partitions[partitionKey])
                share.partitions[partitionKey]++;
            else 
                share.partitions[partitionKey] = 1;

            //update some counters...
            share.counter++;
            if (record.entityName !== undefined) share.hasEntityName++;
            if (record.entityName === 'XXX') share.isXXX++;
        },
        finaly: function whenAllIsDone() {
            console.log("counter = " + share.counter + ". ");
            console.log("has entity name: "+ share.hasEntityName+ ". ")
            console.log("is XXX: " + share.isXXX+ ". ")
            var parts = Object.getOwnPropertyNames(share.partitions)
            console.log("partition keys: " + parts.length + " ...");

            getContext()
                .getResponse()
                .setBody(share);
        }
    });


    //The magic function...
    //also see: https://azure.github.io/azure-cosmosdb-js-server/Collection.html
    function doForAll(task, ctoken) {

        if (!task) throw "Expected one parameter of type: { filter?: (rec?)=>boolean, callback?: (rec?) => void, finaly?: () => void }";
        //Note:
        //the "__" symbol is an alias for var collection = getContext().getCollection(); = aliased by __

        var result = getContext()
            .getCollection()
            .chain()
                .filter(task.filter || function (rec) { return true; })
                .map(task.callback || function (rec) { return undefined; })
            .value({ continuation: ctoken }, function afterBatchCallback (err, feed, options) {
                if (err) throw err;
                if (options.continuation)
                    doForAll(task, options.continuation);
                else if (task.finaly)
                    task.finaly();
            });

        if (!result.isAccepted)
            throw "catastrophic failure";
    }

}

PS:它可能知道该示例使用的数据看起来如何。 这是此类文档的示例:

{ 
    "id": "123",
    "partitionKey": "PART_1",
    "entityName": "EXAMPLE_ENTITY",
    "veryInterestingInfo": "The 'id' property is also the collections id, the 'partitionKey' property happens to be the collections partition key, and all the records in this collection have a 'entityName' property which contains a (non-unique) string"
}