如何在CosmosDB Javascript存储过程中执行批量字段重命名

时间:2018-08-09 14:05:14

标签: azure azure-cosmosdb

我一直遵循here

所示的javascript存储过程示例

下面的代码是尝试编写更新存储的proc示例的修改版本的尝试。这是我想要做的:

  • 我希望不执行单个文档,而是执行 更新提供的查询返回的文档集。
  • (可选)在响应正文中返回更新文档的数量。

代码如下:

function updateSproc(query, update) {
    var collection = getContext().getCollection();
    var collectionLink = collection.getSelfLink();
    var response = getContext().getResponse();
    var responseBody = {
        updated: 0,
        continuation: false
    };

    // Validate input.
    if (!query) throw new Error("The query is undefined or null.");
    if (!update) throw new Error("The update is undefined or null.");

    tryQueryAndUpdate();

    // Recursively queries for a document by id w/ support for continuation tokens.
    // Calls tryUpdate(document) as soon as the query returns a document.
    function tryQueryAndUpdate(continuation) {
        var requestOptions = {continuation: continuation};

        var isAccepted = collection.queryDocuments(collectionLink, query, requestOptions, function (err, documents, responseOptions) {
            if (err) throw err;

            if (documents.length > 0) {
                tryUpdate(documents);
            } 
            else if (responseOptions.continuation) {
                // Else if the query came back empty, but with a continuation token; repeat the query w/ the token.
                tryQueryAndUpdate(responseOptions.continuation);
            } 
            else {
                // Else if there are no more documents and no continuation token - we are finished updating documents.
                responseBody.continuation = false;
                response.setBody(responseBody);
            }
        });

        // If we hit execution bounds - return continuation:true
        if (!isAccepted) {
            response.setBody(responseBody);
        }
    }

    // Updates the supplied document according to the update object passed in to the sproc.
    function tryUpdate(documents) {
        if (documents.length > 0) {
            var requestOptions = {etag: documents[0]._etag};

            // Rename!
            rename(documents[0], update);

            // Update the document.
            var isAccepted = collection.replaceDocument(
                documents[0]._self, 
                documents[0], 
                requestOptions, 
                function (err, updatedDocument, responseOptions) {
                    if (err) throw err;

                    responseBody.updated++;
                    documents.shift();
                    // Try updating the next document in the array.
                    tryUpdate(documents);
                }
            );

            if (!isAccepted) {
                response.setBody(responseBody);
            }
        } 
        else {
            tryQueryAndUpdate();
        }
    }

    // The $rename operator renames a field.
    function rename(document, update) {
        var fields, i, existingFieldName, newFieldName;

        if (update.$rename) {
            fields = Object.keys(update.$rename);
            for (i = 0; i < fields.length; i++) {
                existingFieldName = fields[i];
                newFieldName = update.$rename[fields[i]];

                if (existingFieldName == newFieldName) {
                    throw new Error("Bad $rename parameter: The new field name must differ from the existing field name.")
                } else if (document[existingFieldName]) {
                    // If the field exists, set/overwrite the new field name and unset the existing field name.
                    document[newFieldName] = document[existingFieldName];
                    delete document[existingFieldName];
                } else {
                    // Otherwise this is a noop.
                }
            }
        }
    }
}

我正在通过azure网站门户运行此sproc,这些是我的输入参数:

  • SELECT * FROM root r
  • {$重命名:{A:“ B”}}

我的文档看起来像这样:

{ id: someId, A: "ChangeThisField" }

重命名字段后,我希望它们看起来像这样:

{ id: someId, B: "ChangeThisField" }

我正在尝试使用此代码调试两个问题:

  1. 更新的计数非常不准确。我怀疑我对延续令牌所做的事情确实很愚蠢-问题的一部分是我不确定如何处理延续令牌。
  2. 重命名本身未发生。 console.log()调试表明,我从未进入过重命名功能的if (update.$rename)块。

1 个答案:

答案 0 :(得分:1)

我如下修改了存储过程代码,它对我有用。我没有使用对象或数组作为我的$rename参数,而是使用了oldKeynewKey。如果您确实关心参数的构造,则可以改回rename方法,这不会影响其他逻辑。请参考我的代码:

function updateSproc(query, oldKey, newKey) {
    var collection = getContext().getCollection();
    var collectionLink = collection.getSelfLink();
    var response = getContext().getResponse();
    var responseBody = {
        updated: 0,
        continuation: ""
    };

    // Validate input.
    if (!query) throw new Error("The query is undefined or null.");
    if (!oldKey) throw new Error("The oldKey is undefined or null.");
    if (!newKey) throw new Error("The newKey is undefined or null.");

    tryQueryAndUpdate();

    function tryQueryAndUpdate(continuation) {
        var requestOptions = {
            continuation: continuation, 
            pageSize: 1
        };

        var isAccepted = collection.queryDocuments(collectionLink, query, requestOptions, function (err, documents, responseOptions) {
            if (err) throw err;

            if (documents.length > 0) {
                tryUpdate(documents);
                if(responseOptions.continuation){
                    tryQueryAndUpdate(responseOptions.continuation);
                }else{
                    response.setBody(responseBody);
                }

            }
        });

        if (!isAccepted) {
            response.setBody(responseBody);
        }
    }

    function tryUpdate(documents) {
        if (documents.length > 0) {
            var requestOptions = {etag: documents[0]._etag};
            // Rename!
            rename(documents[0]);

            // Update the document.
            var isAccepted = collection.replaceDocument(
                documents[0]._self, 
                documents[0], 
                requestOptions, 
                function (err, updatedDocument, responseOptions) {
                    if (err) throw err;

                    responseBody.updated++;
                    documents.shift();
                    // Try updating the next document in the array.
                    tryUpdate(documents);
                }
            );

            if (!isAccepted) {
                response.setBody(responseBody);
            }
        } 
    }

    // The $rename operator renames a field.
    function rename(document) {
        if (oldKey&&newKey) {
            if (oldKey == newKey) {
                throw new Error("Bad $rename parameter: The new field name must differ from the existing field name.")
            } else if (document[oldKey]) {       
                document[newKey] = document[oldKey];
                delete document[oldKey];
            }
        }
    }
}

我只有3个测试文档,因此我将pagesize设置为1来测试延续性的用法。

测试文档:

enter image description here

输出

enter image description here

enter image description here

希望它对您有所帮助。有任何问题,请告诉我。