I have a datasheet that contains the ordered data. The sheet consists of thousands of rows identified by the order id. In the second column I have all the data grouped as json string. The new values are added starting from the last row.
This operation works.
My problem starts when I have to update the changes of some values of ids.
The source where I parse data, both for append and update is a json api.
This is my simulation dataSheet:
Start dataSheet
A | B | C | D | E | F | G | |
---|---|---|---|---|---|---|---|
1 | string | shipped | timestamp | id | countitems | destination | delivery |
2 | {"id":"x11","shipped":null,"countItems":"21","destination":"Paris","delivery":null} | x11 | 21 | Paris | |||
3 | {"id":"x167","shipped":null,"countItems":"3","destination":"Lyon","delivery":null} | x167 | 3 | Lyon | |||
4 | {"id":"x89","shipped":null,"countItems":"8","destination":"Berlin","delivery":null} | x89 | 8 | Berlin | |||
5 | {"id":"x9811","shipped":null,"countItems":"2","destination":"Madrid","delivery":null} | x9811 | 2 | Madrid | |||
6 | {"id":"x73","shipped":null,"countItems":"9","destination":"Liverpool","delivery":null} | x73 | 9 | Liverpool |
This is my current procedure:
1) Apply a filter to the json source, selecting the elements where "shipped" is yes.
// My API is for business use, so I can't share URL and token.
// Request and download work perfectly
const loadShipped = () => {return jsonApi().filter(k=>k.shipped == "yes")}
I get this output
var shipped = [
{"id":"x167","shipped":"yes","countItems":"3","destination":"Lyon","delivery":"22/09/2023"}
,{"id":"x9811","shipped":"yes","countItems":"2","destination":"Madrid","delivery":"27/09/2023"}
]
2) Create a json output of column B and apply a filter selecting the elements where "shipped" is null.
const jsDataSheet = () => {
const colJS = SpreadsheetApp.getActiveSpreadsheet().getRange("B5:B")
.getDisplayValues().filter(col=>col[0]);
const data = `[${colJS.filter(o=>o!='').join(',')}]`;
const dataSheetJson = [...new Set(JSON.parse(data))];
return dataSheetJson.filter(k=>!k.shipped)
}
I get this output
var toUpdate = [
{"id":"x167","shipped":null,"countItems":"3","destination":"Lyon","delivery":null}
,{"id":"x9811","shipped":null,"countItems":"2","destination":"Madrid","delivery":null}
]
cons: The columns are not adjacent and usually the two json have different length and sort.
This is the script I'm using, is very slow, this is the problem for me, I have too much data to update and many cells to fill. For this situation I have reduced the number of elements.
const sheet = SpreadsheetApp.getActiveSpreadsheet();
for(var i=0;i<toUpdate.length;i++){
for(var j=0;j<shipped.length;j++){
if(toUpdate[i].id == shipped[j].id){
const time = Date.parse(new Date()) / 1000;
const ship = shipped[j].shipped;
const dDel = shipped[j].delivery;
const newJS =
JSON.stringify({...toUpdate[i]
,timestamp:time
,shipped:ship
,delivery:dDel
});
sheet.getRange(i + 5,2).setValue(newJS)
sheet.getRange(i + 5,3).setValue(ship)
sheet.getRange(i + 5,4).setValue(time)
sheet.getRange(i + 5,8).setValue(dDel)
}
}
}
This is final result
string | shipped | timestamp | id | countItems | destination | delivery |
---|---|---|---|---|---|---|
{"id":"x11","shipped":null,"countItems":"21","destination":"Paris","delivery":null} | x11 | 21 | Paris | |||
{"id":"x167","shipped":null,"countItems":"3","destination":"Lyon","delivery":null} | yes | x167 | 3 | Lyon | 22/09/2023 | |
{"id":"x89","shipped":null,"countItems":"8","destination":"Berlin","delivery":null} | x89 | 8 | Berlin | |||
{"id":"x9811","shipped":null,"countItems":"2","destination":"Madrid","delivery":null} | yes | x9811 | 2 | Madrid | 27/09/2023 | |
{"id":"x73","shipped":null,"countItems":"9","destination":"Liverpool","delivery":null} | x73 | 9 | Liverpool |
The target is to update data once, update string rows and put the values into empty cells, without changing values already added.
This should work:
const shipped /*data from api*/ = [
{
id: 'x167',
shipped: 'yes',
countItems: '3',
destination: 'Lyon',
delivery: '22/09/2023',
},
{
id: 'x9811',
shipped: 'yes',
countItems: '2',
destination: 'Madrid',
delivery: '27/09/2023',
},
];
const sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('[DATA SHEET]'),
dataRange = sheet.getDataRange(),
data = dataRange.getDisplayValues(),
idColIdx = 5 - 1,
idJsonIdx = 2 - 1,
shippedMap = shipped.reduce((m, c) => m.set(c.id, c), new Map());
data.forEach((row) => {
const idx = row[idColIdx];
if (shippedMap.has(idx)) {
const thisShipped = shippedMap.get(idx),
time = Date.parse(new Date()) / 1000,
ship = thisShipped.shipped,
del = thisShipped.delivery,
thisUpdate = [
JSON.stringify({
...JSON.parse(row[idJsonIdx]),
timestamp: time,
shipped: ship,
delivery: del,
}),
ship,
time,
del,
];
[2, 3, 6, 8].map((c) => c - 1).forEach((c, k) => (row[c] = thisUpdate[k]));
}
});
dataRange.setValues(data);
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
const shipped /*data from api*/ = [
{
id: 'x167',
shipped: 'yes',
countItems: '3',
destination: 'Lyon',
delivery: '22/09/2023',
},
{
id: 'x9811',
shipped: 'yes',
countItems: '2',
destination: 'Madrid',
delivery: '27/09/2023',
},
];
const data = [
[
'2',
'{"id":"x167","shipped":null,"countItems":"3","destination":"Lyon","delivery":null}',
'',
'',
'x167',
'3',
'Lyon',
],
[
'3',
'{"id":"x89","shipped":null,"countItems":"8","destination":"Berlin","delivery":null}',
'',
'',
'x89',
'8',
'Berlin',
],
[
'4',
'{"id":"x9811","shipped":null,"countItems":"2","destination":"Madrid","delivery":null}',
'',
'',
'x9811',
'2',
'Madrid',
],
[
'5',
'{"id":"x73","shipped":null,"countItems":"9","destination":"Liverpool","delivery":null}',
'',
'',
'x73',
'9',
'Liverpool',
],
],
idColIdx = 5 - 1,
idJsonIdx = 2 - 1,
shippedMap = shipped.reduce((m, c) => m.set(c.id, c), new Map());
data.forEach((row) => {
const json = JSON.parse(row[idJsonIdx])
const idx = json.id;
if (shippedMap.has(idx)) {
const thisShipped = shippedMap.get(idx),
time = Date.parse(new Date()) / 1000,
ship = thisShipped.shipped,
del = thisShipped.delivery,
thisUpdate = [
JSON.stringify({
...json,
timestamp: time,
shipped: ship,
delivery: del,
}),
ship,
time,
del,
];
[2, 3, 6, 8].map((c) => c - 1).forEach((c, k) => (row[c] = thisUpdate[k]));
}
});
console.log(data);
<!-- https://meta.stackoverflow.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>