Ошибка в веб-приложении Google с использованием URLFetchApp: диапазон превышает пределы сетки при вставке новой строки

С отличным ТАК помогите на предыдущем шаге у меня есть запись на лист, почти работающая с URLFetchApp под учетными данными учетной записи службы в веб-приложении. Код (ниже) работает только с методом "put"; "пост" выдает ошибку. Насколько я понимаю, обновления и вставки могут выполняться с помощью метода "put". Но код генерирует ошибку, когда диапазон относится к новой строке, то есть последняя строка на листе не пуста.

"диапазон превышает пределы сетки при вставке новой строки"

Если необходимо иметь пустые строки (например, добавить 1000 строк), становится ли это ручным заданием по обслуживанию для мониторинга и периодического добавления новых пустых строк? Я ожидал, что «пут» просто добавит новую строку. Есть ли другой метод с URLFetchApp, чтобы сначала добавить строки в «сетку» перед вставкой данных? Спасибо за любое руководство!

function postData(ssID,updateRange,data) {
    if (clientToken) {
     var url= `https://sheets.googleapis.com/v4/spreadsheets/${ssID}/values/${updateRange}?valueInputOption=RAW`
     var options = {
        muteHttpExceptions: true,
        contentType: 'application/json',
        method:'put', 
        payload: JSON.stringify(data),
        headers: { Authorization: 'Bearer ' + clientToken }
        };
    var response= UrlFetchApp.fetch(url,options);
     var responseCode = response.getResponseCode();
     var responseBody = response.getContentText();
        if (responseCode === 200) {
             var responseJson = JSON.parse(responseBody)
               return responseJson;
          } else {
          Logger.log(Utilities.formatString("Request failed. Expected 200, got %d: %s", responseCode, responseBody))
            return responseCode;
          }
      }  else {//handle failed authorization }
      
   } //end postData

Из вашего вопроса я понимаю, что вам необходимо использовать Sheets API с токеном доступа, полученным учетной записью службы. Например, в качестве обходного пути в вашей ситуации, когда ваша учетная запись Google используется совместно с электронной таблицей учетной записи службы, вы можете использовать службу электронных таблиц (SpreadsheetApp). По этому я подумал, что скрипт может стать проще. Как насчет этого? Но, если в вашей ситуации вы не можете этого сделать, не волнуйтесь.

Tanaike 18.03.2022 03:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуй это:

function postData(ssID, updateRange, data) {
  const ss = SpreadsheetApp.openById(ssID);
  const sh = ss.getRange(updateRange).getSheet();//I assumed range is in A1 notation
  const lr = sh.getLastRow();
  if (lr == sh.getMaxRows()) {
    sh.insertRowsAfter(lr, data.length);
  }
  if (clientToken) {
    var url = `https://sheets.googleapis.com/v4/spreadsheets/${ssID}/values/${updateRange}?valueInputOption=RAW`
    var options = {
      muteHttpExceptions: true,
      contentType: 'application/json',
      method: 'put',
      payload: JSON.stringify(data),
      headers: { Authorization: 'Bearer ' + clientToken }
    };
    var response = UrlFetchApp.fetch(url, options);
    var responseCode = response.getResponseCode();
    var responseBody = response.getContentText();
    if (responseCode === 200) {
      var responseJson = JSON.parse(responseBody)
      return responseJson;
    } else {
      Logger.log(Utilities.formatString("Request failed. Expected 200, got %d: %s", responseCode, responseBody))
      return responseCode;
    }
  } else {//handle failed authorization }

  } //end postData
Ответ принят как подходящий

К сожалению, в API Таблиц версии 4 нет метода, который может автоматически добавлять строки, когда заданный диапазон превышает диапазон листа.

Что вы можете сделать, так это получить количество строк определенного листа, используя Метод: электронные таблицы.get, а затем сравнить его с диапазоном, который вы будете использовать для обновления значений. Если количество строк меньше диапазона обновления, используйте Метод: электронные таблицы.batchUpdate для обновления размера листа.

Демо:

Пример листа:

Код:

function request(ssID = "spreadsheet id here",updateRange = "A1499:A1500",data) {
  if (clientToken) {
    var ssGetUrl= `https://sheets.googleapis.com/v4/spreadsheets/${ssID}`
    var options = {
        muteHttpExceptions: true,
        contentType: 'application/json',
        method:'get', 
        headers: { Authorization: 'Bearer ' + clientToken }
        };
    var ssGetresponse= JSON.parse(UrlFetchApp.fetch(ssGetUrl,options));
    var sheets = ssGetresponse.sheets;
    var rowCount = 0;
    var sheetId = 0;
    sheets.forEach(sheet => {
      if (sheet.properties.sheetId == sheetId){
        rowCount = sheet.properties.gridProperties.rowCount
      }
    })
    var num = parseInt(updateRange.split(":")[1].replace(/[^0-9]/g,'')); //remove letters in updateRange and convert it to string
    if (rowCount < num){
      var diff = num - rowCount;
      var resource = {
          "requests": [
            {
              "appendDimension": {
                "length": diff,
                "dimension": "ROWS",
                "sheetId": 0
              }
            }
          ]
        };
      var ssBatchUpdateUrl= `https://sheets.googleapis.com/v4/spreadsheets/${ssID}:batchUpdate`
      var options = {
          muteHttpExceptions: true,
          contentType: 'application/json',
          method:'post',
          payload: JSON.stringify(resource), 
          headers: { Authorization: 'Bearer ' + clientToken }
          };
      var response= JSON.parse(UrlFetchApp.fetch(ssBatchUpdateUrl,options));
    }
    //insert code for updating range values
  }
}

После выполнения кода:

Примечание: Приведенная выше демонстрация предназначена для увеличения количества строк, когда диапазон обновления выходит за пределы фактических строк листа. Например, если у вас есть диапазон, в котором столбец находится за пределами фактического столбца листа, вы можете обновить скрипт, чтобы он также читал столбецКоличество, изменить синтаксический анализатор, чтобы также получить часть столбца нотации A1, и добавить еще одну запись в appendDimension с СТОЛБЕЦ в качестве измерения. .

Я думал, что ваш подход является правильным направлением. Из I have writes to sheet almost working with URLFetchApp under service account credentials я подумал, что в ситуации OP необходимо использовать API листов с токеном доступа, полученным из учетной записи службы. В этом случае я думаю, что Sheets API нельзя использовать с расширенными сервисами Google. Потому что расширенные сервисы Google не могут установить токен доступа. В этой ситуации как насчет изменения вашего скрипта для прямого запроса к конечной точке с помощью UrlFetchApp? Кроме того, OP updateRange может быть A1Notation, включая имя листа.

Tanaike 18.03.2022 03:31

@Tanaike - Спасибо за совет. Я обновил свой ответ.

Nikko J. 18.03.2022 04:57

Спасибо за ответ. Я думаю, что ваш ответ будет полезен не только ОП, но и другим пользователям.

Tanaike 18.03.2022 06:14

Спасибо, Никко и @Tanaike! Пожалуйста, подтвердите: я заменяю // строку комментария к коду в конце вашей функции «запрос» моим кодом «postData» (с поправкой на разницу в «updateRange») — верно? Кроме того, почему в «var resource... request» есть sheetId = 0? Разве это не должен быть лист Id моего «updateRange» («'sheetName'! A1-update-range»)? Я могу передать sheetId и количество строк для добавления в сетку (обычно 1) для значения «diff» — это упростит ваш код только для получения «сообщения» с помощью ssBatchUpdateUrl — правильно?

DougMS 18.03.2022 20:24

Никко и @Tanaike — дополнительный вопрос: в UrlFetchApp есть метод пакетной выборки (запросов). Может ли выборка batchUpdate (Req1: для добавления строк в сетку), а затем выборка updateData (Req2: для вставки данных) выполняться в правильной последовательности с помощью одного fetchAll([{Req1}, {Req2}])?

DougMS 18.03.2022 20:39

@DougMS — 1. Да 2. sheetID 0 — это идентификатор первого листа по умолчанию при создании новой электронной таблицы. 3. Я использовал идентификатор листа 0 только для того, чтобы показать вам, как решить проблему с updateRange is beyond the sheets actual range. Вы можете изменить его, чтобы получить идентификатор листа, используя Метод: электронные таблицы.get4. Да, вы можете это сделать. Опять же, демонстрация предназначена для того, чтобы вы могли понять, как решить проблему. Вы всегда можете изменить его в зависимости от потребностей вашего скрипта.

Nikko J. 19.03.2022 01:28

Еще раз спасибо, Никко. Что касается последнего (№ 5) дополнительного вопроса - я просто беспокоился о том, может ли отправка добавления сетки и отправка данных вместе в методе FetchAll быть уязвимой для проблем асинхронности/времени, когда добавление сетки не будет завершено до отправки данных. .

DougMS 19.03.2022 04:05

@DougMS - Извините, я забыл, что URL-адрес метода: электронные таблицы.batchUpdate (который я использовал для обновления количества строк) отличается от метода: электронные таблицы.значения.batchUpdate (для обновления значений в листах). Вам нужно создать еще один запрос на обновление значения ячейки.

Nikko J. 19.03.2022 06:53

Другие вопросы по теме