#javascript #json #google-apps-script #google-sheets #aws-lambda
#javascript #json #google-apps-script #google-sheets #aws-lambda
Вопрос:
В настоящее время я использую скрипт Google Apps в Google Sheet, который отправляет данные отдельных строк в AWS API Gateway для создания скриншота. На данный момент несколько запросов полезной нагрузки JSON вызывают некоторые сбои лямбда-функции. Итак, я хочу пакетировать данные строк, а затем отправлять как единую полезную нагрузку, чтобы одна функция AWS Lambda могла выполнять несколько скриншотов.
Как я могу пакетировать полезную нагрузку JSON после повторения данных в каждой строке приведенного ниже кода?
function S3payload () {
var PAYLOAD_SENT = "S3 SCREENSHOT DATA SENT";
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
// Add temporary column header for Payload Status new column entries
sheet.getRange('E1').activate();
sheet.getCurrentCell().setValue('payload status');
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn) // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 0; i < data.length; i) {
var row = data[i];
// Assign each row a variable
var index = row[0]; // Col A: Index Sequence Number
var img = row[1]; // Col B: Image Row
var url = row[2]; // Col C: URL Row
var payloadStatus = row[lastColumn - 1]; // Col E: Payload Status (has the payload been sent)
var siteOwner = "email@example.com";
// Prevent from sending payload duplicates
if (payloadStatus !== PAYLOAD_SENT) {
/* Forward the Contact Form submission to the owner of the site
var emailAddress = siteOwner;
var subject = "New contact form submission: " name;
var message = message;*/
//Send payload body to AWS API GATEWAY
//var sheetid = SpreadsheetApp.getActiveSpreadsheet().getId(); // get the actual id
//var companyname = SpreadsheetApp.getActiveSpreadsheet().getName(); // get the name of the sheet (companyname)
var payload = {
"img": img,
"url": url
};
var url = 'https://requestbin.herokuapp.com/vbxpsavc';
var options = {
'method': 'post',
'payload': JSON.stringify(payload)
};
var response = UrlFetchApp.fetch(url,options);
sheet.getRange(startRow i, lastColumn).setValue(PAYLOAD_SENT); // Update the last column with "PAYLOAD_SENT"
SpreadsheetApp.flush(); // Make sure the last cell is updated right away
// Remove temporary column header for Payload Status
sheet.getRange('E1').activate();
sheet.getCurrentCell().clear({contentsOnly: true, skipFilteredRows: true});
}
}
}
Пример отдельной полезной нагрузки JSON
{"img":"https://s3screenshotbucket.s3.amazonaws.com/realitymine.com.png","url":"https://realitymine.com"}
Пример желаемого выходного результата
[
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/gavurin.com.png","url":"https://gavurin.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/google.com.png","url":"https://google.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/amazon.com","url":"https://www.amazon.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/stackoverflow.com","url":"https://stackoverflow.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/duckduckgo.com","url":"https://duckduckgo.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/docs.aws.amazon.com","url":"https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-features.html"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/github.com","url":"https://github.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/github.com/shelfio/chrome-aws-lambda-layer","url":"https://github.com/shelfio/chrome-aws-lambda-layer"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/gwww.youtube.com","url":"https://www.youtube.com"},
{"img":"https://s3screenshotbucket-useast1v5.s3.amazonaws.com/w3docs.com","url":"https://www.w3docs.com"}
]
Комментарии:
1. Я должен извиниться за мое плохое знание английского. К сожалению, из вашего вопроса я не могу понять о
How can I batch the JSON payload after iterating the data on each line in the code below?
. Чтобы правильно понять вашу цель, можете ли вы предоставить пример ввода и вывода, который вы ожидаете? Из этой информации я хотел бы попытаться понять вашу цель.2. Я вижу, у вас рабочая однорядная подача, отлично! Но где ваша попытка отправки в несколько строк? Это не сервис для написания кода. Если вы предпримете попытку и поделитесь проблемами, с которыми сталкиваетесь, ваш вопрос будет воспринят гораздо более благожелательно.
Ответ №1:
Изменения
- Не вызывайте
UrlFetchApp
методы в цикле, если нет другого способа. Хотя Google предлагает щедрую квоту, она не безгранична, и вы быстро израсходуете ее при любом значительном количестве строк и частоте отправки. - Используйте современные функции ES6, такие как
map
, для преобразования строк значений в объекты в формате желаемой полезной нагрузки. Обратите внимание, что вам нужно будет включить V8 runtime, чтобы использовать их.
Ниже приведен выполняемый фрагмент теста, демонстрирующий, как вы могли бы изменить свой скрипт. Я решил исключить из него логику обновления статуса, поскольку вам решать, как обновлять статус в случае сбоя пакетного обновления:
//TEST MOCKS:
const SpreadsheetApp = {
getActiveSheet() {
const Sheet = {
getLastRow() { return 3; },
getLastColumn() { return 5; },
getDataRange() {
const Range = {
getValues() {
return new Array(Sheet.getLastRow())
.fill([])
.map(
(r,ri) => new Array(Sheet.getLastColumn())
.fill(`mock row ${ri}`)
.map((c,ci) => `${c} cell ${ci}`)
);
}
};
return Range;
}
};
return Sheet;
}
};
const UrlFetchApp = {
fetch(uri, options) {
console.log({ uri, options });
}
};
//END MOCKS;
const sendToS3 = () => {
var PAYLOAD_SENT = "S3 SCREENSHOT DATA SENT";
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow() - 1;
var lastColumn = sheet.getLastColumn();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var siteOwner = "email@example.com";
const appURI = 'https://hfcrequestbin.herokuapp.com/vbxpsavb';
const payloads = data.map(([index, img, url]) => ({ img, url }));
const options = {
'method': 'post',
'payload': JSON.stringify(payloads)
};
const response = UrlFetchApp.fetch(appURI, options);
}
sendToS3();
Примечания
- При пакетной обработке полезной нагрузки POST имейте в виду, что существует квота на максимальный размер тела для каждого запроса (в настоящее время 50 МБ).
- Не вызывайте методы ввода-вывода, такие как
getRange
,getValue
в цикле, они медленные по своей природе, используйте пакетные методы, такие какgetDataRange
,getValues
,setValues
и т.д., И выполняйте все модификации только для массивов в памяти. - Используйте
activate
методы только тогда, когда вы явно хотите изменить фокус, не полагайтесь на него для определения диапазона. Просто используйте обычные ссылки на ячейки, полученные с помощью таких методов, какgetRange
.
Комментарии:
1. Хорошее использование mock. Скопирую в своих ответах 🙂
2. @TheMaster — спасибо 🙂 Вчера меня осенило — зачем удалять не поддающиеся редактированию фрагменты, если мы можем издеваться над сервисами?
Ответ №2:
Попробуйте отправить данные в виде списка / массива. И на стороне сервера выполните итерацию по списку / массиву.
например:
{
"payload": [{
"img": "https://s3screenshotbucket.s3.amazonaws.com/website1.com.png",
"url": "https://website1.com"
}, {
"img": "https://s3screenshotbucket.s3.amazonaws.com/website2.com.png",
"url": "https://website2.com"
}]
}