👋

BigQueryのクエリ結果を、Google Cloud Storage にCSVとして出力する

2024/09/16に公開

やりたいこと

  • テーブルデータを Cloud Storage にエクスポートするにあるようなことを、Cloud Run の Node.js でやりたい。
  • ただし公式によると、一つのファイルに1GBまでしか出力できず、その場合には複数ファイルに分割して出力する必要がある。
  • Node.js の bigquery クライントを使って、どうやってそれを実現するのかのソースが見つからなかったので、自分で書いた。

やり方

1. BigQuery のテーブルを、CSVに全部出力

import { BigQuery } from '@google-cloud/bigquery'
import fs from 'fs'
import path from 'path'

const bigquery = new BigQuery()

/**
 * データの集計を行う
 *
 * 使用上、集計結果を上書きすることができないため、もし集計結果を上書きしたい場合は、
 * 前もって該当の latestAggregatedPeriodId を持つデータ群を削除しておく必要がある
 *
 * DELETE FROM \`${PROJECT_ID}.${DATASET_ID}.${TABLE_ID}\`
 * WHERE latestAggregatedPeriodId = '${jsonData.latestAggregatedPeriodId}'
 */
const main = async () => {
  try {
    console.time('export-csv')
    // SQLファイルを読み込む
    const sqlPath = path.join(__dirname, 'sample.sql')
    const sqlQuery = fs.readFileSync(sqlPath, 'utf-8')
    const options = {
      query: sqlQuery,
      location: 'asia-northeast1',
      destinationTable: {
        projectId: PROJECT_ID,
        datasetId: DATASET_ID,
        tableId: TABLE_ID,
      },
      // 書き込みモードを指定 (WRITE_TRUNCATE, WRITE_APPEND, WRITE_EMPTY)
      // 毎回新しく書き直す
      writeDisposition: 'WRITE_TRUNCATE',
    }

    const [job] = await bigquery.createQueryJob(options)
    console.log(`Job ${job.id} started.`)

    // ジョブが完了するまで待つ
    await job.promise()

    console.log(`Job ${job.id} completed.`)

    const [extractJob] = await bigquery
      .dataset(DATASET_ID)
      .table(VOTER_POINT_AGGREGATION_TABLE_ID)
      .extract(admin.storage().bucket('bucket-name').file('sample-*.csv'), {
        location: 'asia-northeast1',
        format: 'CSV',
      })
    console.log(`Extract Job ${extractJob.id} created.`)

    console.timeEnd('export-csv')
  } catch (e) {
    console.error('Error', e)
  }
}

main()

2. BigQuery のテーブルのクエリ結果(データの一部)を CSVに出力

  • EXPORT DATA を使う
EXPORT DATA
  OPTIONS(
  uri='gs://bucket-name/sample-*.csv',
  format='CSV',
  header=true,
  overwrite=true) AS
SELECT
  *
FROM `project-id.dataset-id.table-id`;

GitHubで編集を提案

Discussion