简体   繁体   English

Google Apps脚本电子表格:错误

[英]Google apps script spreadsheet:error

I work for a public school district and have written a script to take data from a Google form response sheet and filter it into separate sheets based on which school the information relates to. 我在一家公立学区工作,并且编写了一个脚本来从Google表单响应表中获取数据,并根据信息所涉及的学校将其过滤到单独的表中。 Using the tutorial located at https://developers.google.com/apps-script/guides/sheets . 使用位于https://developers.google.com/apps-script/guides/sheets的教程。 The modified script is 1300 lines long (including some explinations) and has been running smoothly up until recently. 修改后的脚本长1300行(包括一些错误),直到最近一直运行良好。

The script now returns numerous errors. 脚本现在返回许多错误。 Most commonly I see errors such as: 最常见的是,我看到以下错误:

"Service timed out: Spreadsheets (line 40, file "Transfer/SortID/Copy/Sort")" “服务超时:电子表格(第40行,文件“ Transfer / SortID / Copy / Sort”))

"Service error: Spreadsheets (line 40, file "Transfer/SortID/Copy/Sort")" “服务错误:电子表格(第40行,文件“ Transfer / SortID / Copy / Sort”))

The line that is flagged in the error is 错误中标记的行是

"headersRange.setValues([columnNames]);" “headersRange.setValues([COLUMNNAMES]);”

I have tried everything that I can think of including creating a new target spreadsheet. 我已经尝试了所有可以想到的一切,包括创建新的目标电子表格。

I have included the beginning section of the code below. 我已经在下面的代码中包含了开始部分。 Again, this script was running great up until recently. 同样,该脚本一直运行到最近。 (Last time it ran successfully was 5/6) (上次成功运行的时间是5/6)

Thanks in advance for your help! 在此先感谢您的帮助!

// This is where the data used in this example will be retrieved from:
// https://docs.google.com/a/psdschools.org/spreadsheet/ccc?key=0AswYUpTPhetrdFYxUEJZSkxHeVdfSk5pajh3UjYxaUE&usp=drive_web#gid=0
function TransferAndSort() {{
var DATA_SPREADSHEET_ID = "0AswYUpTPhetrdFYxUEJZSkxHeVdfSk5pajh3UjYxaUE"

//update data

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];

  var dataSs = SpreadsheetApp.openById(DATA_SPREADSHEET_ID);
  var dataSheet = dataSs.getSheets()[0];

  // Fetch all the data
  var data = getRowsData(dataSheet);

  // This is the data we want to display
  var columnNames = ["Last Name","First Name", "ID Number", "School", "Date Written", "Purpose", "Requested Route #", "Requested Stop Location", "Type of Student", "Contact Made"];


// Index data by School name
  var dataBySchool = {};
  var schools = [];
  for (var i = 0; i < data.length; ++i) {
    var rowData = data[i];
    if (!dataBySchool[rowData.school]) {
      dataBySchool[rowData.school] = [];
      schools.push(rowData.school);
    }
    dataBySchool[rowData.school].push(rowData);
  }

  schools.sort();
  var headerBackgroundColor = dataSheet.getRange(1, 1).getBackgroundColor();
  for (var i = 0; i < schools.length; ++i) {
    var sheet = ss.getSheetByName(schools[i]) ||
      ss.insertSheet(schools[i], ss.getSheets().length);
    sheet.clear();
    var headersRange = sheet.getRange(1, 1, 1, columnNames.length);
    headersRange.setValues([columnNames]);
    headersRange.setBackgroundColor(headerBackgroundColor);
    setRowsData(sheet, dataBySchool[schools[i]]);
  }
}

// setRowsData fills in one row of data per object defined in the objects Array.
// For every Column, it checks if data objects define a value for it.
// Arguments:
//   - sheet: the Sheet Object where the data will be written
//   - objects: an Array of Objects, each of which contains data for a row
//   - optHeadersRange: a Range of cells where the column headers are defined. This
//     defaults to the entire first row in sheet.
//   - optFirstDataRowIndex: index of the first row where data should be written. This
//     defaults to the row immediately below the headers.
function setRowsData(sheet, objects, optHeadersRange, optFirstDataRowIndex) {
  var headersRange = optHeadersRange || sheet.getRange(1, 1, 1, sheet.getMaxColumns());
  var firstDataRowIndex = optFirstDataRowIndex || headersRange.getRowIndex() + 1;
  var headers = normalizeHeaders(headersRange.getValues()[0]);

  var data = [];
  for (var i = 0; i < objects.length; ++i) {
    var values = []
    for (j = 0; j < headers.length; ++j) {
      var header = headers[j];
      // If the header is non-empty and the object value is 0...
      if ((header.length > 0) && (objects[i][header] == 0)) {
        values.push(0);
      }
      // If the header is non-empty or the object value is empty...
      else if ((!(header.length > 0)) || (objects[i][header]=='')) {
        values.push('');
      }
      else {
        values.push(objects[i][header]);
      }
    }
    data.push(values);
  }

  var destinationRange = sheet.getRange(firstDataRowIndex, headersRange.getColumnIndex(),
                                        objects.length, headers.length);
  destinationRange.setValues(data);
}

// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
//   - sheet: the sheet object that contains the data to be processed
//   - range: the exact range of cells where the data is stored
//       This argument is optional and it defaults to all the cells except those in the first row
//       or all the cells below columnHeadersRowIndex (if defined).
//   - columnHeadersRowIndex: specifies the row number where the column names are stored.
//       This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
  var headersIndex = columnHeadersRowIndex || range ? range.getRowIndex() - 1 : 1;
  var dataRange = range ||
    sheet.getRange(headersIndex + 1, 1, sheet.getMaxRows() - headersIndex, sheet.getMaxColumns());
  var numColumns = dataRange.getEndColumn() - dataRange.getColumn() + 1;
  var headersRange = sheet.getRange(headersIndex, dataRange.getColumn(), 1, numColumns);
  var headers = headersRange.getValues()[0];
  return getObjects(dataRange.getValues(), normalizeHeaders(headers));
}

// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
//   - data: JavaScript 2d array
//   - keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
  var objects = [];
  for (var i = 0; i < data.length; ++i) {
    var object = {};
    var hasData = false;
    for (var j = 0; j < data[i].length; ++j) {
      var cellData = data[i][j];
      if (isCellEmpty(cellData)) {
        continue;
      }
      object[keys[j]] = cellData;
      hasData = true;
    }
    if (hasData) {
      objects.push(object);
    }
  }
  return objects;
}

// Returns an Array of normalized Strings.
// Empty Strings are returned for all Strings that could not be successfully normalized.
// Arguments:
//   - headers: Array of Strings to normalize
function normalizeHeaders(headers) {
  var keys = [];
  for (var i = 0; i < headers.length; ++i) {
    keys.push(normalizeHeader(headers[i]));
  }
  return keys;
}

// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
//   - header: string to normalize
// Examples:
//   "First Name" -> "firstName"
//   "Market Cap (millions) -> "marketCapMillions
//   "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
function normalizeHeader(header) {
  var key = "";
  var upperCase = false;
  for (var i = 0; i < header.length; ++i) {
    var letter = header[i];
    if (letter == " " && key.length > 0) {
      upperCase = true;
      continue;
    }
    if (!isAlnum(letter)) {
      continue;
    }
    if (key.length == 0 && isDigit(letter)) {
      continue; // first character must be a letter
    }
    if (upperCase) {
      upperCase = false;
      key += letter.toUpperCase();
    } else {
      key += letter.toLowerCase();
    }
  }
  return key;
}

// Returns true if the cell where cellData was read from is empty.
// Arguments:
//   - cellData: string
function isCellEmpty(cellData) {
  return typeof(cellData) == "string" && cellData == "";
}

// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
  return char >= 'A' && char <= 'Z' ||
    char >= 'a' && char <= 'z' ||
    isDigit(char);
}

// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
  return char >= '0' && char <= '9';
}

I don't have a great answer for you, but this might help or at least offer a little bit of insight. 我没有一个很好的答案,但这可能会有所帮助,或者至少会提供一些见识。 I'm experiencing similar problems with an add-on that I'm developing. 我正在开发的插件遇到类似的问题。 The issue seems to be related to calling sheet.clear(). 该问题似乎与调用sheet.clear()有关。 After a sheet.clear(), certain operations take a long time the first time they are called. 在sheet.clear()之后,某些操作在第一次调用时会花费很长时间。 In our case, we're seeing sheet.getMaxColumns() take upwards of 20s after calling sheet.clear(), whereas it takes only milliseconds if we remove the sheet.clear() call. 在我们的例子中,我们看到sheet.getMaxColumns()在调用sheet.clear()之后花费了20秒以上的时间,而如果我们删除sheet.clear()调用仅花费了毫秒。 If I call it twice in a row, the first call takes a long time, but the second call is very fast again. 如果我连续两次通话,则第一个通话会花费很长时间,但是第二个通话又很快。 I have confirmed that the same behavior is true even if switching to sheet.clearContents(). 我已经确认,即使切换到sheet.clearContents(),相同的行为也是正确的。

I'm hoping this is some sort of bug recently introduced by Google that will be addressed quickly, as we don't really have a workaround to calling sheet.clear() at this point in time. 我希望这是Google最近引入的某种错误,将很快得到解决,因为我们目前还没有一种解决方法来调用sheet.clear()。

Hope this helps, and good luck! 希望这会有所帮助,并祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM