2
votes

I am trying to fetch some range of data from google sheet via app script.
Let's have an example. I have 96 data rows in google sheet, I want to fetch 10 rows.
From Front-end side the call is based on scrolling event to fetch every next 10 row data.
I have tried below code.

function doGet(request){
  var ss = SpreadsheetApp.openById("MY SHEET ID");
  var sheet = ss.getSheetByName("Products");
  return getUsers(sheet,request); 
}

function getUsers(sheet,request){
  var jo = {};
  var dataArray = [];
  // every time from, where is passed from Frontend, like 2-10, 12-10, 22-10, etc...
  var from = request.parameter.from;
  var where = request.parameter.where;
  // by this if condition, getting data from 1 to 90
  if((sheet.getLastRow()-1)>=(from+where)){
    var rows = sheet.getRange(from,1,from+where, sheet.getLastColumn()).getValues();
    for(var i = 0, l= rows.length; i<l ; i++){
      var dataRow = rows[i];
      var record = {};
      record['ProductId'] = dataRow[0];
      // ...
      // some more column data fetching here
      // ...
      dataArray.push(record);
    }  
    jo.user = dataArray;
    var result = JSON.stringify(jo);
    return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
  }
  // tried to get last 6 data through below code
  else{
    if(from <= (sheet.getLastRow() - 1)){
      var rows = sheet.getRange(from,1,sheet.getLastRow()-1, sheet.getLastColumn()).getValues();
      for(var i = 0, l= rows.length; i<l ; i++){
        var dataRow = rows[i];
        var record = {};
        record['ProductId'] = dataRow[0];
        // ...
        // some more column data fetching here
        // ...
        dataArray.push(record);
      }  
      jo.user = dataArray;
      var result = JSON.stringify(jo);
      return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
    }
  }
}  

By this code, I am getting values up to 90 with chunks of 10 rows, but at the end, the last 6 data I am not able to get.
Is there any logic to get those records? I have tried to achieve through last if statement but couldn't get.
Thanks in Advance!

Edit:
as per the solution from Taniake, Getting ProductId column perfectly,
Moreover, If there are multiple columns like ProductId, ProductName, ProductImage, etc..
Range Might be
From

const values = sheet.getRange(from, 1, sheet.getLastRow() - from - where >= 0 ? where : sheet.getLastRow() - from + 1, 1).getValues();

To

const values = sheet.getRange(from, 1, sheet.getLastRow() - from - where >= 0 ? where : sheet.getLastRow() - from + 1, sheet.getLastColumn()).getValues();

how to map those values to JSON constant namely "result" in the solution provided?
2
Do you need both from and where parameters if you will only ever return 10 results? This can be cleaned up easily enough, but it would be helpful if you'd clarify your motivation and spec. As I rule, I would 1) combine both of these functions into one, 2) just pull in the entire spreadsheet range in question and then slice it as needed with your parameters (this will also eliminate the need for the conditional), 3) use map and reduce rather than loops. This will greatly reduce the odds of fencepost errors and make things a lot easier to read.Frank

2 Answers

2
votes

Here's a start at a refactor. A few things I don't understand and need clarification on:

  1. Why are you adding from and where for the loop? If I set from=10; where=20, I get results from 10 through 39. I'm guessing that is not what you want.
  2. Obviously you'll want to clean up the default values for myfunc.
function doGet(request)
{
  return myfunc(request.parameter.from, request.parameter.where);
}

function myfunc(from=10, where=20){
  let sheet = SpreadsheetApp.openById("1CP1n-B87RD_BfffrOKVemmbqQ4-rq3W5t59x90tX0VA").getSheetByName("Products");
  var jo = {user:[]};

  const rawdata = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
  const data = rawdata.slice(from, where);
  
  data.map((row, idx, arr)=>{
     let record = {};
     record['ProductId'] = row[0];
     jo.user.push(record);
  });

  return JSON.stringify(jo);
} 
2
votes

I thought that in your case, the retrieved values might be required to be modified. So how about the following modification? In your script, the values are retrieved from the column "A". So, this is also reflected to the modified script.

Modified script:

When your script is modified, please modify as follows.

var rows = sheet.getRange(from,1,from+where, sheet.getLastColumn()).getValues();
var rows = sheet.getRange(from, 1, where, 1).getValues();

and

var rows = sheet.getRange(from,1,sheet.getLastRow()-1, sheet.getLastColumn()).getValues();
var rows = sheet.getRange(from, 1, sheet.getLastRow() - from + 1, 1).getValues();

Or, as other pattern, how about the following sample script?

Sample script 1:

In this sample, your getUsers is modified. In this pattern, the range is changed for from and where and the values are retrieved from the specific range.

function getUsers(sheet,request){
  var from = request.parameter.from;
  var where = request.parameter.where;
  
  const values = sheet.getRange(from, 1, sheet.getLastRow() - from - where >= 0 ? where : sheet.getLastRow() - from + 1, 1).getValues();
  const result = JSON.stringify({user: values.map(([a]) => ({ProductId: a}))});
  return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}

Sample script 2:

In this sample, your getUsers is modified. In this pattern, all values are retrieved for the column "A" and the specific values are retrieved using splice. In this case, from and where can be directly used. I think that this might be the same flow with Frank's comment.

function getUsers(sheet,request){
  var from = request.parameter.from;
  var where = request.parameter.where;
  
  const values = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues().splice(from, where);
  const result = JSON.stringify({user: values.map(([a]) => ({ProductId: a}))});
  return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}

Note:

  • When you modified the script, please redeploy the Web Apps as new version. By this, the latest script is reflected to Web Apps. Please be careful this.

References:

Added:

When the columns are 3 columns like "ProductId", "ProductName" and "ProductImage", the sample script 1 and 2 is as follows.

From:

const values = sheet.getRange(from, 1, sheet.getLastRow() - from - where >= 0 ? where : sheet.getLastRow() - from + 1, 1).getValues();
const result = JSON.stringify({user: values.map(([a]) => ({ProductId: a}))});

To:

const values = sheet.getRange(from, 1, sheet.getLastRow() - from - where >= 0 ? where : sheet.getLastRow() - from + 1, sheet.getLastColumn()).getValues();
const result = JSON.stringify({user: values.map(([a,b,c]) => ({ProductId: a: ProductName: b, ProductImage: c}))});

or

From:

const values = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues().splice(from, where);
const result = JSON.stringify({user: values.map(([a]) => ({ProductId: a}))});

To:

const values = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues().splice(from, where);
const result = JSON.stringify({user: values.map(([a,b,c]) => ({ProductId: a: ProductName: b, ProductImage: c}))});
  • When you want to expand this, please modify [a,b,c] to [a,b,c,d,e,f,,,] and {ProductId: a: ProductName: b, ProductImage: c} to {ProductId: a: ProductName: b, ProductImage: c, key1: d, key2: e, key3: f}.