gsheet
This commit is contained in:
parent
da2b8885a4
commit
10805cd4b3
@ -153,6 +153,7 @@ Fastify
|
||||
FileReader
|
||||
GBK
|
||||
GatsbyJS
|
||||
GitLab
|
||||
Goja
|
||||
HTML
|
||||
HTML5
|
||||
|
@ -8,8 +8,12 @@ import TabItem from '@theme/TabItem';
|
||||
This demo uses [`node-google-spreadsheet`](https://theoephraim.github.io/node-google-spreadsheet)
|
||||
to interact with Google Sheets v4 API.
|
||||
|
||||
Code that does not directly relate to SheetJS APIs are tucked away. Click on
|
||||
the "click to show" blocks to see the code snippets.
|
||||
:::caution
|
||||
|
||||
Google Sheets deprecates APIs quickly and there is no guarantee that the
|
||||
referenced API version will be available in the future.
|
||||
|
||||
:::
|
||||
|
||||
## Initial Configuration
|
||||
|
||||
@ -46,97 +50,10 @@ module.exports = async(ID) => {
|
||||
|
||||
</details>
|
||||
|
||||
## Exporting Document Data to a File
|
||||
## Export Document Data
|
||||
|
||||
The goal is to create an XLSB export from a Google Sheet. Google Sheets does
|
||||
not natively support the XLSB format. SheetJS fills the gap. [The last subsection](#how-to-run-export-example) includes detailed instructions for running locally.
|
||||
|
||||
### Connecting to the Document
|
||||
|
||||
This uses the `common.js` helper from above:
|
||||
|
||||
<details><summary><b>Code</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
/* Connect to Google Sheet */
|
||||
const ID = "<google sheet id>";
|
||||
const doc = await require("./common")(ID);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Creating a New Workbook
|
||||
|
||||
`XLSX.utils.book_new()` creates an empty workbook with no worksheets:
|
||||
|
||||
```js
|
||||
/* create a blank workbook */
|
||||
const wb = XLSX.utils.book_new();
|
||||
```
|
||||
|
||||
### Looping across the Document
|
||||
|
||||
|
||||
`doc.sheetsByIndex` is an array of worksheets in the Google Sheet Document.
|
||||
|
||||
<details><summary><b>Code</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
/* Loop across the Document sheets */
|
||||
for(let i = 0; i < doc.sheetsByIndex.length; ++i) {
|
||||
const sheet = doc.sheetsByIndex[i];
|
||||
/* Get the worksheet name */
|
||||
const name = sheet.title;
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Convert a Google Sheets sheet to a SheetJS Worksheet
|
||||
|
||||
The idea is to extract the raw data from the Google Sheet headers and combine
|
||||
with the raw data rows to produce a large array of arrays.
|
||||
|
||||
<details><summary><b>Code</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
/* get the header and data rows */
|
||||
await sheet.loadHeaderRow();
|
||||
const header = sheet.headerValues;
|
||||
const rows = await sheet.getRows();
|
||||
|
||||
/* construct the array of arrays */
|
||||
const aoa = [header].concat(rows.map(r => r._rawData));
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
This can be converted to a SheetJS worksheet using `XLSX.utils.aoa_to_sheet`:
|
||||
|
||||
|
||||
```js
|
||||
/* generate a SheetJS Worksheet */
|
||||
const ws = XLSX.utils.aoa_to_sheet(aoa);
|
||||
```
|
||||
|
||||
`XLSX.utils.book_append_sheet` will add the worksheet to the workbook:
|
||||
|
||||
```js
|
||||
/* add to workbook */
|
||||
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||
```
|
||||
|
||||
### Generating an XLSB file
|
||||
|
||||
`XLSX.writeFile` will write a file in the file system:
|
||||
|
||||
```js
|
||||
/* write to SheetJS.xlsb */
|
||||
XLSX.writeFile(wb, "SheetJS.xlsb");
|
||||
```
|
||||
|
||||
### How to Run Export Example
|
||||
not natively support the XLSB format. SheetJS fills the gap.
|
||||
|
||||
<details><summary><b>How to run locally</b> (click to show)</summary>
|
||||
|
||||
@ -225,151 +142,56 @@ const ID = "<google sheet ID>";
|
||||
|
||||
</details>
|
||||
|
||||
## Updating a Document from a Local File
|
||||
### Convert a Single Sheet
|
||||
|
||||
The goal is to refresh a Google Sheet based on a local file. The problem can
|
||||
be broken down into a few steps. [The last subsection](#how-to-run-update-example)
|
||||
includes detailed instructions for running locally.
|
||||
|
||||
### Reading the Workbook File
|
||||
|
||||
`XLSX.readFile` can read files from the file system. The following line reads
|
||||
`sheetjs.xlsx` from the current directory:
|
||||
The idea is to extract the raw data from the Google Sheet headers and combine
|
||||
with the raw data rows to produce a large array of arrays.
|
||||
|
||||
```js
|
||||
const XLSX = require("xlsx");
|
||||
const wb = XLSX.readFile("sheetjs.xlsx");
|
||||
async function wb_append_sheet(sheet, name, wb) {
|
||||
/* get the header and data rows */
|
||||
await sheet.loadHeaderRow();
|
||||
const header = sheet.headerValues;
|
||||
const rows = await sheet.getRows();
|
||||
|
||||
/* construct the array of arrays */
|
||||
const aoa = [header].concat(rows.map(r => r._rawData));
|
||||
|
||||
/* generate a SheetJS Worksheet */
|
||||
const ws = XLSX.utils.aoa_to_sheet(aoa);
|
||||
|
||||
/* add to workbook */
|
||||
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||
}
|
||||
```
|
||||
|
||||
### Connecting to the Document
|
||||
### Convert a Workbook
|
||||
|
||||
This uses the `common.js` helper from above:
|
||||
|
||||
<details><summary><b>Code</b> (click to show)</summary>
|
||||
`doc.sheetsByIndex` is an array of worksheets in the Google Sheet Document. By
|
||||
looping across the sheets, the entire workbook can be written:
|
||||
|
||||
```js
|
||||
/* Connect to Google Sheet */
|
||||
const ID = "<google sheet id>";
|
||||
const doc = await require("./common")(ID);
|
||||
```
|
||||
async function doc_to_wb(doc) {
|
||||
/* Create a new workbook object */
|
||||
const wb = XLSX.utils.book_new();
|
||||
|
||||
</details>
|
||||
/* Loop across the Document sheets */
|
||||
for(let i = 0; i < doc.sheetsByIndex.length; ++i) {
|
||||
const sheet = doc.sheetsByIndex[i];
|
||||
/* Get the worksheet name */
|
||||
const name = sheet.title;
|
||||
|
||||
### Clearing the Document
|
||||
|
||||
Google Sheets does not allow users to delete every worksheet. The snippet
|
||||
deletes every worksheet after the first, then clears the first worksheet.
|
||||
|
||||
<details><summary><b>Code</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
/* clear workbook */
|
||||
{
|
||||
/* delete all sheets after the first sheet */
|
||||
const old_sheets = doc.sheetsByIndex;
|
||||
for(let i = 1; i < old_sheets.length; ++i) {
|
||||
await old_sheets[i].delete();
|
||||
/* Add sheet to workbook */
|
||||
await add_sheet_to_wb(sheet, name, wb);
|
||||
}
|
||||
/* clear first worksheet */
|
||||
old_sheets[0].clear();
|
||||
|
||||
return wb;
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
## Update Document Data
|
||||
|
||||
### Update First Worksheet
|
||||
|
||||
In the SheetJS workbook object, worksheet names are stored in the `SheetNames`
|
||||
property. The first worksheet name is `wb.SheetNames[0]`:
|
||||
|
||||
```js
|
||||
const name = wb.SheetNames[0];
|
||||
```
|
||||
|
||||
The `Sheets` property is an object whose keys are sheet names and whose values
|
||||
are worksheet objects.
|
||||
|
||||
```js
|
||||
const ws = wb.Sheets[name];
|
||||
```
|
||||
|
||||
In the Google Sheet, `doc.sheetsByIndex[0]` is a reference to the first sheet:
|
||||
|
||||
```js
|
||||
const sheet = doc.sheetsByIndex[0];
|
||||
```
|
||||
|
||||
#### Update Sheet Name
|
||||
|
||||
The worksheet name is assigned by using the `updateProperties` method. The
|
||||
desired sheet name is the name of the first worksheet from the file.
|
||||
|
||||
```js
|
||||
/* update worksheet name */
|
||||
await sheet.updateProperties({title: name});
|
||||
```
|
||||
|
||||
#### Update Worksheet Data
|
||||
|
||||
`sheet.addRows` reads an Array of Arrays of values. `XLSX.utils.sheet_to_json`
|
||||
can generate this exact shape with the option `header: 1`. Unfortunately
|
||||
Google Sheets requires at least one "Header Row". This can be implemented by
|
||||
converting the entire worksheet to an Array of Arrays and setting the header
|
||||
row to the first row of the result:
|
||||
|
||||
```js
|
||||
/* generate array of arrays from the first worksheet */
|
||||
const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
|
||||
|
||||
/* set document header row to first row of the AOA */
|
||||
await sheet.setHeaderRow(aoa[0]);
|
||||
|
||||
/* add the remaining rows */
|
||||
await sheet.addRows(aoa.slice(1));
|
||||
```
|
||||
|
||||
### Add the Other Worksheets
|
||||
|
||||
Each name in the SheetJS Workbook `SheetNames` array maps to a worksheet. The
|
||||
loop over the remaining worksheet names looks like
|
||||
|
||||
```js
|
||||
for(let i = 1; i < wb.SheetNames.length; ++i) {
|
||||
/* wb.SheetNames[i] is the sheet name */
|
||||
const name = wb.SheetNames[i];
|
||||
/* wb.Sheets[name] is the worksheet object */
|
||||
const ws = wb.Sheets[name];
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
#### Appending a Worksheet to the Document
|
||||
|
||||
`doc.addSheet` accepts a properties object that includes the worksheet name:
|
||||
|
||||
```js
|
||||
const sheet = await doc.addSheet({title: name});
|
||||
```
|
||||
|
||||
This creates a new worksheet, sets the tab name, and returns a reference to the
|
||||
created worksheet.
|
||||
|
||||
#### Update Worksheet Data
|
||||
|
||||
This is identical to the first worksheet code:
|
||||
|
||||
```js
|
||||
/* generate array of arrays from the first worksheet */
|
||||
const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
|
||||
|
||||
/* set document header row to first row of the AOA */
|
||||
await sheet.setHeaderRow(aoa[0]);
|
||||
|
||||
/* add the remaining rows */
|
||||
await sheet.addRows(aoa.slice(1));
|
||||
```
|
||||
|
||||
### How to Run Update Example
|
||||
The goal is to refresh a Google Sheet based on a local file.
|
||||
|
||||
<details><summary><b>How to run locally</b> (click to show)</summary>
|
||||
|
||||
@ -485,15 +307,132 @@ const ID = "<google sheet ID>";
|
||||
|
||||
</details>
|
||||
|
||||
## Using the Raw File Exports
|
||||
### Clear the Document
|
||||
|
||||
Google Sheets does not allow users to delete every worksheet. This function
|
||||
deletes every worksheet after the first, then clears the first worksheet:
|
||||
|
||||
```js
|
||||
/* clear google sheets doc */
|
||||
async function doc_clear(doc) {
|
||||
/* delete all sheets after the first sheet */
|
||||
const old_sheets = doc.sheetsByIndex;
|
||||
for(let i = 1; i < old_sheets.length; ++i) await old_sheets[i].delete();
|
||||
|
||||
/* clear first worksheet */
|
||||
old_sheets[0].clear();
|
||||
}
|
||||
```
|
||||
|
||||
### Update First Sheet
|
||||
|
||||
There are two steps: "update worksheet name" and "update worksheet data":
|
||||
|
||||
#### Update Sheet Name
|
||||
|
||||
The worksheet name is assigned by using the `updateProperties` method. The
|
||||
desired sheet name is the name of the first worksheet from the file.
|
||||
|
||||
```js
|
||||
async function doc_update_first_sheet_name(doc, wb) {
|
||||
/* get first worksheet name */
|
||||
const wsname = wb.SheetNames[0];
|
||||
|
||||
/* get first gsheet */
|
||||
const sheet = doc.sheetsByIndex[0];
|
||||
|
||||
/* update worksheet name */
|
||||
await sheet.updateProperties({title: wsname});
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Sheet Data
|
||||
|
||||
`sheet.addRows` reads an Array of Arrays of values. `XLSX.utils.sheet_to_json`
|
||||
can generate this exact shape with the option `header: 1`. Unfortunately
|
||||
Google Sheets requires at least one "Header Row". This can be implemented by
|
||||
converting the entire worksheet to an Array of Arrays and setting the header
|
||||
row to the first row of the result:
|
||||
|
||||
```js
|
||||
async function doc_update_first_sheet_data(doc, wb) {
|
||||
/* get first worksheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
/* generate array of arrays from the first worksheet */
|
||||
const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
|
||||
|
||||
/* get first gsheet */
|
||||
const sheet = doc.sheetsByIndex[0];
|
||||
/* set document header row to first row of the AOA */
|
||||
await sheet.setHeaderRow(aoa[0]);
|
||||
|
||||
/* add the remaining rows */
|
||||
await sheet.addRows(aoa.slice(1));
|
||||
}
|
||||
```
|
||||
|
||||
### Append Remaining Worksheets
|
||||
|
||||
Each name in the SheetJS Workbook `SheetNames` array maps to a worksheet. The
|
||||
list of names not including the first sheet is `wb.SheetNames.slice(1)`.
|
||||
|
||||
There are two steps for each sheet: "create new sheet" and "load data".
|
||||
|
||||
Due to JavaScript `async` idiosyncrasies, a plain `for` loop must be used:
|
||||
|
||||
```js
|
||||
async function doc_append_remaining_sheets(doc, wb) {
|
||||
const names = wb.SheetNames.slice(1);
|
||||
|
||||
/* loop across names */
|
||||
for(let i = 0; i < names.length; ++i) {
|
||||
/* wb.SheetNames[i] is the sheet name */
|
||||
const name = wb.SheetNames[i];
|
||||
/* wb.Sheets[name] is the worksheet object */
|
||||
const ws = wb.Sheets[name];
|
||||
|
||||
/* create new google sheet */
|
||||
const sheet = await doc_add_new_sheet(doc, name);
|
||||
/* load sheet with data */
|
||||
await sheet_load_from_ws(sheet, ws);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Add a New Worksheet
|
||||
|
||||
`doc.addSheet` accepts a properties object that includes the worksheet name:
|
||||
|
||||
```js
|
||||
async function doc_add_new_sheet(doc, name) {
|
||||
return await doc.addSheet({title: name});
|
||||
}
|
||||
```
|
||||
|
||||
This creates a new worksheet, sets the tab name, and returns a reference to the
|
||||
created worksheet.
|
||||
|
||||
#### Update Worksheet Data
|
||||
|
||||
```js
|
||||
async function sheet_load_from_ws(sheet, ws) {
|
||||
/* generate array of arrays from the first worksheet */
|
||||
const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
|
||||
|
||||
/* set document header row to first row of the AOA */
|
||||
await sheet.setHeaderRow(aoa[0]);
|
||||
|
||||
/* add the remaining rows */
|
||||
await sheet.addRows(aoa.slice(1));
|
||||
}
|
||||
```
|
||||
|
||||
## Raw File Exports
|
||||
|
||||
`node-google-spreadsheet` can download the XLSX or ODS export of the document.
|
||||
The functions return NodeJS `Buffer` data that can be parsed using SheetJS.
|
||||
|
||||
<details><summary><b>Sample Code</b> (click to show)</summary>
|
||||
|
||||
SheetJS can read data from XLSX files and ODS files. This example prints the
|
||||
worksheet names and CSV exports of each sheet.
|
||||
This example prints the worksheet names and CSV exports of each sheet.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="xlsx" label="XLSX">
|
||||
@ -501,27 +440,30 @@ worksheet names and CSV exports of each sheet.
|
||||
```js
|
||||
const XLSX = require("xlsx");
|
||||
|
||||
/* Connect to Google Sheet */
|
||||
const ID = "<google sheet id>";
|
||||
const doc = await require("./common")(ID);
|
||||
(async() => {
|
||||
/* Connect to Google Sheet */
|
||||
const ID = "<google sheet id>";
|
||||
const doc = await require("./common")(ID);
|
||||
|
||||
/* Get XLSX export */
|
||||
const buf = await doc.downloadAsXLSX();
|
||||
/* Get file export */
|
||||
// highlight-next-line
|
||||
const buf = await doc.downloadAsXLSX();
|
||||
|
||||
/* Parse with SheetJS */
|
||||
const wb = XLSX.read(buf);
|
||||
/* Parse with SheetJS */
|
||||
const wb = XLSX.read(buf);
|
||||
|
||||
/* Loop over the worksheet names */
|
||||
wb.SheetNames.forEach(name => {
|
||||
/* Print the name to the console */
|
||||
console.log(name);
|
||||
/* Loop over the worksheet names */
|
||||
wb.SheetNames.forEach(name => {
|
||||
/* Print the name to the console */
|
||||
console.log(name);
|
||||
|
||||
/* Get the corresponding worksheet object */
|
||||
const sheet = wb.Sheets[name];
|
||||
/* Get the corresponding worksheet object */
|
||||
const sheet = wb.Sheets[name];
|
||||
|
||||
/* Print a CSV export of the worksheet */
|
||||
console.log(XLSX.utils.sheet_to_csv(sheet));
|
||||
});
|
||||
/* Print a CSV export of the worksheet */
|
||||
console.log(XLSX.utils.sheet_to_csv(sheet));
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -531,30 +473,31 @@ wb.SheetNames.forEach(name => {
|
||||
```js
|
||||
const XLSX = require("xlsx");
|
||||
|
||||
/* Connect to Google Sheet */
|
||||
const ID = "<google sheet id>";
|
||||
const doc = await require("./common")(ID);
|
||||
(async() => {
|
||||
/* Connect to Google Sheet */
|
||||
const ID = "<google sheet id>";
|
||||
const doc = await require("./common")(ID);
|
||||
|
||||
/* Get XLSX export */
|
||||
const buf = await doc.downloadAsODS();
|
||||
/* Get file export */
|
||||
// highlight-next-line
|
||||
const buf = await doc.downloadAsODS();
|
||||
|
||||
/* Parse with SheetJS */
|
||||
const wb = XLSX.read(buf);
|
||||
/* Parse with SheetJS */
|
||||
const wb = XLSX.read(buf);
|
||||
|
||||
/* Loop over the worksheet names */
|
||||
wb.SheetNames.forEach(name => {
|
||||
/* Print the name to the console */
|
||||
console.log(name);
|
||||
/* Loop over the worksheet names */
|
||||
wb.SheetNames.forEach(name => {
|
||||
/* Print the name to the console */
|
||||
console.log(name);
|
||||
|
||||
/* Get the corresponding worksheet object */
|
||||
const sheet = wb.Sheets[name];
|
||||
/* Get the corresponding worksheet object */
|
||||
const sheet = wb.Sheets[name];
|
||||
|
||||
/* Print a CSV export of the worksheet */
|
||||
console.log(XLSX.utils.sheet_to_csv(sheet));
|
||||
});
|
||||
/* Print a CSV export of the worksheet */
|
||||
console.log(XLSX.utils.sheet_to_csv(sheet));
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
</details>
|
||||
</Tabs>
|
Loading…
Reference in New Issue
Block a user