代码之家  ›  专栏  ›  技术社区  ›  nciao

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

  •  1
  • nciao  · 技术社区  · 6 年前

    我一直在遵循下面的javascript存储过程示例 here

    下面的代码试图编写更新存储过程示例的修改版本。我要做的是:

    • 我希望执行 更新由提供的查询返回的文档集。
    • (可选)返回响应正文中已更新文档的计数。

    代码如下:

    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门户网站运行此存储过程,以下是我的输入参数:

    • 从根r中选择*
    • {$重命名:{A:“B”}

    我的文档看起来像这样:

    { id: someId, A: "ChangeThisField" }
    

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

    { id: someId, B: "ChangeThisField" }
    

    我试图调试这段代码的两个问题:

    1. 更新后的计数极不准确。我怀疑我用延续标记做了一件非常愚蠢的事情-部分问题是我不确定该怎么处理它。
    2. 重命名本身没有发生。 console.log() 调试表明我从未进入 if (update.$rename) 在重命名函数中阻止。
    1 回复  |  直到 6 年前
        1
  •  1
  •   Jay Gong    6 年前

    我修改了您的存储过程代码,如下所示,它对我有效 $rename 参数,我用过 oldKey newKey 相反。如果您确实关心参数的构造,可以更改 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 测试continuation的用法。

    试验文件:

    enter image description here

    输出 :

    enter image description here

    enter image description here

    希望对你有帮助。有什么问题,请告诉我。