Как добавить медиафайл для API BigQuery Rest с помощью UrlFetchApp? - PullRequest
2 голосов
/ 23 сентября 2019

Мне нужно передать данные в BigQuery из моего дополнения скрипта Google Apps.

Но мне нужно использовать только свою учетную запись службы (мне нужно вставлять данные в мою таблицу BigQuery, а непользовательская таблица BigQuery)

Я следовал этому примеру: https://developers.google.com/apps-script/advanced/bigquery#load_csv_data

Поскольку расширенная служба скриптов приложений изначально не поддерживает учетную запись службы, поэтому мне нужно немного изменить этот пример:

Вместо использования Advanced Service BigQuery мне нужно получить токен OAuth из своей учетной записи службы, а затем использовать BigQuery Rest API для выполнения той же работы:

Это то, что я сделал:

function getBigQueryService() {
  return (
    OAuth2.createService('BigQuery')
      // Set the endpoint URL.
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the private key and issuer.
      .setPrivateKey(PRIVATE_KEY)
      .setIssuer(CLIENT_EMAIL)

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getScriptProperties())

      // Caching
      .setCache(CacheService.getUserCache())

      // Locking
      .setLock(LockService.getUserLock())

      // Set the scopes.
      .setScope('https://www.googleapis.com/auth/bigquery')
  )
}

export const insertLog = (userId, type) => {
  const bigQueryService = getBigQueryService()
  if (!bigQueryService.hasAccess()) {
    console.error(bigQueryService.getLastError())
    return
  }

  const projectId = bigqueryCredentials.project_id
  const datasetId = 'usage'
  const tableId = 'logs'
  const row = {
    timestamp: new Date().toISOString(),
    userId,
    type,
  }

  const data = Utilities.newBlob(convertToNDJson(row), 'application/octet-stream')

  // Create the data upload job.
  const job = {
    configuration: {
      load: {
        destinationTable: {
          projectId,
          datasetId,
          tableId,
        },
        sourceFormat: 'NEWLINE_DELIMITED_JSON',
      },
    },
  }

  const url = `https://bigquery.googleapis.com/upload/bigquery/v2/projects/${projectId}/jobs`
  const headers = {
    Authorization: `Bearer ${bigQueryService.getAccessToken()}`,
    'Content-Type': 'application/json',
  }

  const options = {
    method: 'post',
    headers,
    payload: JSON.stringify(job),
  }

  try {
    const response = UrlFetchApp.fetch(url, options)
    const result = JSON.parse(response.getContentText())

    console.log(JSON.stringify(result, null, 2))
  } catch (err) {
    console.error(err)
  }
}

Как вы можете видеть из моего кода, я получаю данные Blob (которые являются фактическими данными JSON, которые мне нужно поместить в таблицу BigQuery), используя эту строку:

const data = Utilities.newBlob(convertToNDJson(row), 'application/octet-stream')

Но я неНе знаю, где использовать это data с BigQuery Rest API

В документации не упоминается: https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/insert

Как это можно сделать?Спасибо.

1 Ответ

0 голосов
/ 24 сентября 2019

Я могу решить эту проблему, используя библиотеку Tanaike FetchApp:

https://github.com/tanaikech/FetchApp#fetch

У кого-нибудь возникнет эта проблема в будущем: пожалуйста, проверьте мой комментарий в коде, чтобы понять, что было сделано.

Оказывается, переменная job обрабатывается как metadata, а переменная data обрабатывается как file в объекте данных формы

// First you need to convert the JSON to Newline Delimited JSON,
// then turn the whole thing to Blob using Utilities.newBlob

const data = Utilities.newBlob(convertToNDJson(row), 'application/octet-stream')

  // Create the data upload job.
  const job = {
    configuration: {
      load: {
        destinationTable: {
          projectId,
          datasetId,
          tableId,
        },
        sourceFormat: 'NEWLINE_DELIMITED_JSON',
      },
    },
  }

  const url = `https://bigquery.googleapis.com/upload/bigquery/v2/projects/${projectId}/jobs?uploadType=multipart`
  const headers = {
    Authorization: `Bearer ${bigQueryService.getAccessToken()}`,
  }

  const form = FetchApp.createFormData() // Create form data
  form.append('metadata', Utilities.newBlob(JSON.stringify(job), 'application/json'))
  form.append('file', data)

  const options = {
    method: 'post',
    headers,
    muteHttpExceptions: true,
    body: form,
  }

  try {
    FetchApp.fetch(url, options)
  } catch (err) {
    console.error(err)
  }

Примечание. При созданииучетную запись службы, выберите роль BigQuery Admin или любую роль, у которой есть разрешение bigquery.jobs.create

https://cloud.google.com/bigquery/docs/access-control#bigquery-roles

Поскольку в противном случае у вас будет ошибка

У пользователя нет разрешения bigquery.jobs.create ...

...