Google 应用制作工具批量更新数据库记录

Google App Maker updating DB records in batches

我们有一个 Google App Maker 应用程序使用 Google Cloud SQL 表格。我们的位置是中欧的布拉格,app.saveRecords() 至少需要令人难以置信的 240 毫秒。我们尝试了很多方法,包括更改实例的位置,但都没有解决问题。

幸运的是,解决方案是批量插入新记录。我之前的帖子 [ ].

中的答案很好地解决了这个问题

如果有人为我们提供一个简单的代码来批量更新数据库中的记录,我们将不胜感激[服务器端脚本]。这样,我们不仅可以批量插入全新的记录,还可以快速更新已保存在数据库中的记录的数据。

假设我们有一个包含 3 个自定义字段的数据库:

product code | product availability | price

+ 包含数据的示例数组:

ourData[0] = ['pc001','in stock','99'];
ourData[1] = ['pc002','out of stock','49'];
ourData[2] = ['pc003','out of stock','199'];
ourData[3] = ['pc004','in stock','149'];
ourData[4] = ['pc005','in stock','299'];

...我们想使用关键字 "product code" 将可用性和价格数据分配给特定的数据库行。如果在数据库中没有找到产品代码,那么我们向数据库中插入一条新记录。

多个单行 inserts/updates 需要 Google 欧盟的 App Maker 用户太长时间,因为即使 SQL 实例位于欧盟,查询也会转到美国。 运行 这可能会分批打破目前 Google 美国以外的 App Maker 限制。非常感谢您的帮助,使 Google App Maker 成为世界各地初学者的绝佳工具。

这个问题可以通过使用正确的服务器脚本来解决,我强烈建议您阅读 official documentation 中服务器脚本的工作原理。请密切注意 查询记录 示例。

因此,以前面的解决方案示例为基础,可以稍作修改以满足您的需求。它应该是这样的:

function saveData(){

    //get the data
    var data = getData();

    var totalRecords = data.length;
    var batchLimit = 2000;
    var totalRounds = Math.ceil(totalRecords / batchLimit);
    var round = 1;
    var roundlimit = batchLimit;
    var currentItem = 0;

    do{
        var recordsToSave = [];

        for(var i=currentItem; i<roundlimit; i++){

            var recordData = data[i];
            var productCode = recordData[0];

            //check if the record already exists
            var query = app.models.testDB.newQuery();
            query.filters.productCode._equals = productCode;
            var productRecord = query.run()[0];

            //if non existent, create a new one
            if(!productRecord){
                productRecord = app.models.testDB.newRecord();
                productRecord.productCode = productCode;
            }

            productRecord.availability = recordData[1];
            productRecord.price = recordData[2];
            recordsToSave.push(newProduct);
        }

        if(recordsToSave.length){
            app.saveRecords(recordsToSave);
        }

        currentItem += batchLimit;
        roundlimit += batchLimit;
        round++;

    } while(round <= totalRounds);

}

在线程中其他人的帮助下,我设法将插入或更新记录的时间减少到 50 毫秒。此外,我已经测试了 insert/update 10000 条记录到包含 60 个字段的 table。在这种情况下,速度为每条记录 60 毫秒。特此,我向任何人(可能会发现它有用的人)提供我的最终代码。感谢您提供所有有用的答案和评论!

/* We use Google Cloud SQL Table "testDB" that contains these fields:
   - Id (the default primary key for DBs in Google App Maker)
   - productCode
   - availability
   - price

   We have an array called "data" which contains the data [productCode, availability, price] we want to save to the database.
*/

function saveDataNew(){
    var data = [];
    data[0] = ['pc1','in stock','99'];
    data[1] = ['pc2','out of stock','129'];
    data[2] = ['pc3','in stock','78'];
    data[3] = ['pc4','in stock','95'];

    //load all the records in the DB (no filter is used)
    var query = app.models.testDB.newQuery();
    var records = query.run();
    console.log("Found " + records.length + " records in the database.");

    //create an array to help us find DB's Id for each unique productCode.
    var helpingArray = [];
    for (var x in records) {
      var product = records[x]; //get each record in the DB
      helpingArray.push([product.productCode,product.Id]); //save this record's productCode and Id into the helping array
    }

    //setting up the writing in batches
    var totalRecords = data.length;
    var batchLimit = 500; //size of a batch round - number of lines for each app.saveRecords();
    var roundlimit;
    if(totalRecords < batchLimit){
      roundlimit = totalRecords;
    }
    else{
      roundlimit = batchLimit;     
    }
    var totalRounds = Math.ceil(totalRecords / batchLimit);
    var round = 1;
    var currentItem = 0;

    //start writing in batches
    do{ 
        var recordsToSave = [];
        //create or update a record in the DB for each line of our data within one batch round
        for(var i=currentItem; i<roundlimit; i++){
          var wantedCode = data[i][0]; //get the productCode of the current line of the data array
          var orderNum = -1; //create a variable to find the order number of the productCode in the helping array
          for(var z=0; z<helpingArray.length; z++){ //search for the productCode in the helping array
            if(helpingArray[z][0]==wantedCode){
              orderNum = z; //save the line's number if the productCode is found in the helpingArray
              continue;
            }
          }
          var productRecord;
          if (orderNum == -1){ //there was no line with the productCode found the helpingArray => create a new record
                productRecord = app.models.testDB.newRecord();
                productRecord.productCode = data[i][0]; 
          }
          else{ //the productCode was found in the helpingArray => edit the existing record in the DB 
                productRecord = records[orderNum];
          }
          //provide the record with the data
          productRecord.availability = data[i][1];
          productRecord.price = data[i][2];

          //cumulate records and save them once the batch round is finished
          recordsToSave.push(productRecord); 
        }

        //a batch round has been finished, save records if there are any
        if(recordsToSave.length){
            console.log("Records saved: "+recordsToSave.length);
            app.saveRecords(recordsToSave);
        }

        currentItem += batchLimit;
        round++; 

        if (totalRecords < round*batchLimit){
          roundlimit = totalRecords;  
        }
        else{
          roundlimit += batchLimit;    
        }
    } while(round <= totalRounds);
}