9
votes

Google Sheets document can contain some sheets. First is default and '0'. Generally for any sheet there is address like this:

https://docs.google.com/spreadsheets/d/(spreadsheetId)/edit#gid=(sheetId)

with both spreadsheetId and sheetId.

But in API documentation there is no mention of how to use sheetId. I can only read and edit default sheet for given spreadsheetId.

If in request from code presented in exemplary link I added sheetId property I got error:

{ 
    message: 'Invalid JSON payload received. Unknown name "sheetId": Cannot bind query parameter. Field \'sheetId\' could not be found in request message.',
    domain: 'global',
    reason: 'badRequest' 
}

How to get access to other sheets than default in Google Sheets API and read or update fields in them?

4
@I'-'I, thank your hint I solved this problem. Please add this as answer, no comment and we close this topic.Daniel
amazing the docs still don't mention this in 2020, have a look at developers.google.com/sheets/api/reference/rest/v4/…cryanbhu

4 Answers

5
votes

As written here, range parameter can include sheet names like,

Sheet1!A1

If you must use a sheet id instead of sheet name, You can use any of the alternate end points which uses dataFilter, like spreadsheets.values.batchUpdateByDataFilter instead of spreadsheets.values.batchUpdate. You can then use sheetId in request body at data.dataFilter.gridRange.sheetId.

However, developer metadata is the preferred method of permanently associating objects(sheets/ranges/columns) to variables, where user modifications are expected on such objects.

0
votes

The initial blank empty tab that is always present when a new Google Sheet is created always has sheetId 0 assigned to it.

Subsequently created sheetIds are randomized ten digit numbers. Only the first tab has sheetId 0. Even if you rename a sheet, it's ID remains constant. IDs are never reused - they remain unique within a given sheet.

Using the Google Drive API, access to a Google Sheet is instantiated using the sheet's Google Drive file ID.

Once you have instantiated access to the particular Google Sheet file, you can then reference each tab within the sheet tab and manipulate information, format, etc within a tab of the sheet, by using the 'sheetId' nomenclature.

Here is a PHP example of renaming a Google Sheet's tab name using sheetId 0.

<?php
/*
 *   Google Sheets API V4 / Drive API V3, rename existing sheet tab example
 *
 */
$fileID = '/* pass your Google Sheet Google Drive file ID here */';
$client = new Google_Client();
$client->useApplicationDefaultCredentials(); // the JSON service account key location as defined in $_SERVER
$client->setApplicationName('API Name');
$client->addScope(Google_Service_Drive::DRIVE);
$client->setAccessType('offline');
$client->setSubject('API Instance Subject');
$sheet = new Google_Service_Sheets($client);
$sheetList = $sheet->spreadsheets->get($fileID);

/*
 *   iterate through all Google Sheet tabs in this sheet
 */
 $homeFlag = FALSE;
 foreach($sheetList->getSheets() as $sheetRecord) {
        /*
         *   if match, save $sheetTabID from Google Sheet tab 
         */
         if ($sheetRecord['properties']['sheetId'] == 0) {
                 $sheetTabID = $sheetRecord['properties']['sheetId'];
                 $sheetTabTitle = $sheetRecord['properties']['title'];
                 $homeFlag = TRUE;
            }
    }

/*
 *   if $homeFlag is TRUE, you found your desired tab, so rename tab in Google Sheet
 */
 if ($homeFlag) {
         $newTabName = 'NotTabZero';
         $sheetRenameTab = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest(array('requests' => array('updateSheetProperties' => array('properties' => array('sheetId' => $sheetTabID, 'title' => $newTabName), 'fields' => 'title'))));
         $sheetResult = $sheet->spreadsheets->batchUpdate($sheetID,$sheetRenameTab);
    }
?>
0
votes

Here is my working example for "rename sheet in spreadsheet by sheetId" function. You can use other methods from Google Spreadsheets API Docs in the same way. Hope it will be helpful for somebody


    <?php
function getClient()   //standard auth function for google sheets API
{
    $clientConfigPath = __DIR__ . '/google_credentials/client_secret.json';
    $client = new Google_Client();
    $client->setApplicationName('Google Sheets API PHP Quickstart');
    $client->setScopes(Google_Service_Sheets::SPREADSHEETS);
    $client->setAuthConfig($clientConfigPath);
    $client->setAccessType('offline');

    // Load previously authorized credentials from a file.
    $credentialsPath = (__DIR__ . '/google_credentials/credentials.json');
    if (file_exists($credentialsPath)) {
        $accessToken = json_decode(file_get_contents($credentialsPath), true);
    } else {
        // Request authorization from the user.
        $authUrl = $client->createAuthUrl();
        printf("Open the following link in your browser:\n%s\n", $authUrl);
        print 'Enter verification code: ';
        $authCode = trim(fgets(STDIN));

        // Exchange authorization code for an access token.
        $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);

        // Store the credentials to disk.
        if (!file_exists(dirname($credentialsPath))) {
            mkdir(dirname($credentialsPath), 0700, true);
        }
        file_put_contents($credentialsPath, json_encode($accessToken));
        printf("Credentials saved to %s\n", $credentialsPath);
    }
    $client->setAccessToken($accessToken);

    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
        $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
    }
    return $client;
}


function renameSheet(string $sheetId, string $newTitle, string $spreadsheetId)
{
    // Get the API client and construct the service object.
    $client = getClient();
    $service = new Google_Service_Sheets($client);

    $requests = [
        new Google_Service_Sheets_Request([
            'updateSheetProperties' => [
                'properties' => [
                    'sheetId' => $sheetId,
                    'title' => $newTitle,
                ],
                'fields' => 'title'
            ]
        ])
    ];

    $batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
        'requests' => $requests
    ]);

    return $service->spreadsheets->batchUpdate($spreadsheetId, $batchUpdateRequest);
}

UPDATE If you want to get sheet title by sheetId, you can use following function

function getSpreadsheetInfo($spreadsheetId)  
{
    $client = getClient();
    $service = new Google_Service_Sheets($client);

    $response = $service->spreadsheets->get($spreadsheetId);
    return $response;
}

function getSheets($spreadsheetId)  
{
    $spreadsheet_info = getSpreadsheetInfo($spreadsheetId);
    $sheets_info = [];
    foreach ($spreadsheet_info as $item) {
        $sheet_id = $item['properties']['sheetId'];
        $sheet_title = $item['properties']['title'];
        $sheets_info[$sheet_id] = $sheet_title;
    }
    return $sheets_info;
}

$sheets_info_array = getSheets($YOUR_SPREADSHEET_ID_HERE);

$sheets_info_array will be equal

array (
    "sheet_id1(int)" => 'sheet_title1',
    "sheet_id2(int)" => 'sheet_title3',
)

so you can get $your_sheet_id's title as $sheets_info_array[$your_sheet_id]

0
votes

Essentially we need to use dataFilters to target a specific sheet by ID.

@TheMaster pointed me in the right direction but I found the answers confusing so I just want to share my working example for Node.js.

Here's how to get the value of cell B2 from a sheet that has ID 0123456789

const getValueFromCellB2 = async () => {
  const SPREADSHEET_ID = 'INSERT_SPREADSHEET_ID';
  const SHEET_ID = 0123456789;
  // TODO: replace above values with real IDs.
  const google = await googleConnection();
  const sheetData = await google.spreadsheets.values
    .batchGetByDataFilter({
      spreadsheetId: SPREADSHEET_ID,
      resource: {
        dataFilters: [
          {
            gridRange: {
              sheetId: SHEET_ID,
              startRowIndex: 1,
              endRowIndex: 2,
              startColumnIndex: 1,
              endColumnIndex: 2,
            },
          },
        ],
      },
    })
    .then((res) => res.data.valueRanges[0].valueRange.values);

  return sheetData[0][0];
}

// There are many ways to auth with Google... Here's one:
const googleConnection = async () => {
  const auth = await google.auth.getClient({
    keyFilename: path.join(__dirname, '../../secrets.json'),
    scopes: 'https://www.googleapis.com/auth/spreadsheets',
  });

  return google.sheets({version: 'v4', auth});
}

To simply read data we're using batchGetByDataFilter where dataFilters is an array of separate filter objects. The gridRange filter (one of many) allows us to specify a sheetId and range of cells to return.