GoでGoogle Sheets APIを利用する【セルの更新】

今回はGoでGoogle スプレッドシートへの書き込みについてまとめたいと思います。
Google Sheets APIを利用する事前準備、サービスアカウントの認証については[こちら](https://qiita.com/takenoko-gohan/items/2cd6ab9463334e4acfcb)を参照してください。
Go言語、Google Sheets APIは学習途中なので間違った記述、非推奨なコードの書き方があった場合、ご指摘いただければ幸いです。



## 単一の範囲を更新する場合

単一の範囲対して更新を行う際は、`Spreadsheets.Values.Update()`を使用します。
`Spreadsheets.Values.Update()`の引数は、`(スプレッドシートID, 更新範囲, sheets.ValueRange)`となります。



### サンプルコード

```go
package main

import (
	"encoding/json"
	"io/ioutil"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"golang.org/x/oauth2/jwt"
	"google.golang.org/api/sheets/v4"
)

type credentialsJson struct {
	Email      string `json:"client_email"`
	PrivateKey string `json:"private_key"`
}

func main() {
    // サービスアカウントでの認証
	bytes, _ := ioutil.ReadFile("credentials.json")
	var credentials credentialsJson
	json.Unmarshal(bytes, &credentials)

	conf := &jwt.Config{
		Email:      credentials.Email,
		PrivateKey: []byte(credentials.PrivateKey),
		TokenURL:   google.JWTTokenURL,
		Scopes: []string{
            // スプレッドシートの読み込みと書き込みを許可
			"https://www.googleapis.com/auth/spreadsheets",
		},
	}

	client := conf.Client(oauth2.NoContext)

	sheetsSrv, _ := sheets.New(client)
	// スプレッドシートの指定
	spreadsheetId := ""

	ctx := context.Background()

    // 更新範囲の指定
	valueRange := "A1:B2"
    // 更新値の指定
	rb := &sheets.ValueRange{
		MajorDimension: "ROWS",
		Values: [][]interface{}{
			[]interface{}{"123", "hoge"},
			[]interface{}{"1.23", "=B1&B1"},
		},
	}

	sheetsSrv.Spreadsheets.Values.Update(spreadsheetId, valueRange, rb).ValueInputOption("USER_ENTERED").Context(ctx).Do()
}
```

実行結果

|      |  A   |    B     |
| :--: | :--: | :------: |
|  1   | 123  |   hoge   |
|  2   | 1.23 | hogehoge |



### スプレッドシートID

更新するスプレッドシートを指定する際に使用します。スプレッドシートIDは使用するスプレッドシートのURLから取得することができます。



https&#58;//docs.google.com/spreadsheets/d/**<u>hogehoge</u>**/edit#gid=0



上記のhogehogeの部分がスプレッドシートIDとなります。



### 更新範囲

更新する範囲を指定する際は、GUIと同様で下記のように指定します。

| 例               | 備考                                                 |
| ---------------- | ---------------------------------------------------- |
| "シート名"       | シート名が一致するシートの全体を範囲とする。         |
| "A1:B2"          | 最初のシート（一番左のタブ）のA1からB2を範囲とする。 |
| "シート名!A1:B2" | シート名が一致するシートのA1からB2を範囲とする。     |



### sheets.ValueRange



#### 	majorDimension

行と列どちらで更新するか指定します。デフォルトの値は`ROWS`です。

| 値      | 備考             |
| ------- | ---------------- |
| ROWS    | 行で更新します。 |
| COLUMNS | 列で更新します。 |



サンプルコードの`MajorDimension: "ROWS"`の`ROWS`を`COLUMNS`に変更して実行すると下記のように更新されます。

実行結果

|      |  A   |    B     |
| :--: | :--: | :------: |
|  1   | 123  |   1.23   |
|  2   | hoge | 1.231.23 |



#### values

セルに書き込む値は`Values`で指定します。記述する値は、`interface`型の2次元配列である必要があります。



### クエリパラメータ



#### valueInputOption

更新する値の解釈方法を指定します。

| 値           | 備考                                      |
| ------------ | ----------------------------------------- |
| RAW          | 更新する値は解釈されません。              |
| USER_ENTERED | GUIで更新するときと同様の解釈がされます。 |



サンプルコードの`sheetsSrv.Spreadsheets.Values.Update(spreadsheetId, valueRange, rb).ValueInputOption("USER_ENTERED").Context(ctx).Do()`の`USER_ENTERED`を`RAW`に変更して実行すると下記のように数式が解釈されずに文字列として更新されます。

実行結果

|      |  A   |   B    |
| :--: | :--: | :----: |
|  1   | 123  |  hoge  |
|  2   | 1.23 | =B1&B1 |



## 複数の範囲を更新する場合

複数の範囲をまとめて更新する場合は、`Spreadsheets.Values.BatchUpdate()`を使用します。
`Spreadsheets.Values.BatchUpdate()`の引数は、`(スプレッドシートID, sheets.BatchUpdateValuesRequest)`となります。



### サンプルコード

```go
package main

import (
	"encoding/json"
	"io/ioutil"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"golang.org/x/oauth2/jwt"
	"google.golang.org/api/sheets/v4"
)

type credentialsJson struct {
	Email      string `json:"client_email"`
	PrivateKey string `json:"private_key"`
}

func main() {
    // サービスアカウントでの認証
	bytes, _ := ioutil.ReadFile("credentials.json")
	var credentials credentialsJson
	json.Unmarshal(bytes, &credentials)

	conf := &jwt.Config{
		Email:      credentials.Email,
		PrivateKey: []byte(credentials.PrivateKey),
		TokenURL:   google.JWTTokenURL,
		Scopes: []string{
            // スプレッドシートの読み込みと書き込みを許可
			"https://www.googleapis.com/auth/spreadsheets",
		},
	}

	client := conf.Client(oauth2.NoContext)

	sheetsSrv, _ := sheets.New(client)
	// スプレッドシートの指定
	spreadsheetId := ""

	ctx := context.Background()

    // 更新範囲と更新値の指定
	valueRange1 := "A1:B2"
	values1 := [][]interface{}{
		[]interface{}{"123", "hoge"},
		[]interface{}{"1.23", "=B1&B1"},
	}

	valueRange2 := "C3:D4"
	values2 := [][]interface{}{
		[]interface{}{"456", "fuga"},
		[]interface{}{"4.56", "=D3&D3"},
	}

	rb := &sheets.BatchUpdateValuesRequest{
		ValueInputOption: "USER_ENTERED",
		Data: []*sheets.ValueRange{
			&sheets.ValueRange{
				Range:          valueRange1,
				MajorDimension: "ROWS",
				Values:         values1,
			},
			&sheets.ValueRange{
				Range:          valueRange2,
				MajorDimension: "ROWS",
				Values:         values2,
			},
		},
	}

	sheetsSrv.Spreadsheets.Values.BatchUpdate(spreadsheetId, rb).Context(ctx).Do()
}
```

実行結果

|      |  A   |    B     |  C   |    D     |
| :--: | :--: | :------: | :--: | :------: |
|  1   | 123  |   hoge   |      |          |
|  2   | 1.23 | hogehoge |      |          |
|  3   |      |          | 456  |   fuga   |
|  4   |      |          | 4.56 | fugafuga |



### sheets.BatchUpdateValuesRequest



#### valueInputOption

`Spreadsheets.Values.Update()`のクエリパラメータと同様です。



#### data

`Data`に記述する値は`sheets.ValueRange`の1次元配列である必要があります。
更新範囲は`sheets.ValueRange`内の`Range`で指定します。
それ以外は`Spreadsheets.Values.Update()`と同様です。



## 枠線やセルの色と合わせて更新する場合

枠線やセルの色と合わせてセルの値を更新する場合は、`Spreadsheets.BatchUpdate()`を使用します。
`Spreadsheets.BatchUpdate()`の引数は、`(スプレッドシートID, sheets.BatchUpdateSpreadsheetRequest)`となります。



### サンプルコード

```go
package main

import (
	"encoding/json"
	"io/ioutil"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"golang.org/x/oauth2/jwt"
	"google.golang.org/api/sheets/v4"
)

type credentialsJson struct {
	Email      string `json:"client_email"`
	PrivateKey string `json:"private_key"`
}

func main() {
    // サービスアカウントでの認証
	bytes, _ := ioutil.ReadFile("credentials.json")
	var credentials credentialsJson
	json.Unmarshal(bytes, &credentials)

	conf := &jwt.Config{
		Email:      credentials.Email,
		PrivateKey: []byte(credentials.PrivateKey),
		TokenURL:   google.JWTTokenURL,
		Scopes: []string{
            // スプレッドシートへの読み込みと書き込みを許可
			"https://www.googleapis.com/auth/spreadsheets",
		},
	}

	client := conf.Client(oauth2.NoContext)

	sheetsSrv, _ := sheets.New(client)
	// スプレッドシートの指定
	spreadsheetId := ""

	ctx := context.Background()

	requests := []*sheets.Request{
		&sheets.Request{
			UpdateCells: &sheets.UpdateCellsRequest{
				Fields: "UserEnteredValue",
				Rows: []*sheets.RowData{
					&sheets.RowData{
                        // 更新値を指定
						Values: []*sheets.CellData{
							&sheets.CellData{
								UserEnteredValue: &sheets.ExtendedValue{
									NumberValue: 123,
								},
							},
							&sheets.CellData{
								UserEnteredValue: &sheets.ExtendedValue{
									StringValue: "hoge",
								},
							},
						},
					},
					&sheets.RowData{
                        // 更新値を指定
						Values: []*sheets.CellData{
							&sheets.CellData{
								UserEnteredValue: &sheets.ExtendedValue{
									NumberValue: 1.23,
								},
							},
							&sheets.CellData{
								UserEnteredValue: &sheets.ExtendedValue{
									FormulaValue: "=B1&B1",
								},
							},
						},
					},
				},
                // 更新範囲を指定
				Range: &sheets.GridRange{
					EndColumnIndex:   2,
					EndRowIndex:      2,
                    // シートIDを指定
					SheetId:          0,
					StartColumnIndex: 0,
					StartRowIndex:    0,
				},
			},
		},
	}

	rb := &sheets.BatchUpdateSpreadsheetRequest{
		Requests: requests,
	}

	sheetsSrv.Spreadsheets.BatchUpdate(spreadsheetId, rb).Context(ctx).Do()
}
```

実行結果

|      |  A   |    B     |
| :--: | :--: | :------: |
|  1   | 123  |   hoge   |
|  2   | 1.23 | hogehoge |



### sheets.BatchUpdateSpreadsheetRequest



#### fields

`CellData`内で更新するフィールドを指定します。ワイルドカードも指定できるようですが、非推奨のようです。



#### rows

セルの値は`sheets.RowData`の配列で指定します。
更新値の型は下記で指定します。

| 値           | 備考                                 |
| ------------ | ------------------------------------ |
| NumberValue  | 左記で指定した値は数値になります。   |
| StringValue  | 左記で指定した値は文字列になります。 |
| FormulaValue | 左記で指定した値は数式になります。   |



#### range

`Range`では、更新するシートと範囲を指定します。

`StartRowIndex`と`EndRowIndex`で範囲の開始行と終了行を指定します。
`StartColumnIndex`と`EndColumnIndex`で範囲の開始列と終了列を指定します。

`SheetId`では、更新するシートを指定します。
シートIDは使用するシートを開いたときのURLから取得することができます。



https&#58;//docs.google.com/spreadsheets/d/hogehoge/edit#**<u>gid=0</u>**



上記の`gid=`以降の部分がシートIDとなります。



## 参考資料

単一の範囲を更新する場合

[Method: spreadsheets.values.update](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update)

複数の範囲を更新する場合

[Method: spreadsheets.values.batchUpdate](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate)

枠線やセルの色と合わせて更新する場合

[Method: spreadsheets.batchUpdate](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/batchUpdate)