1

firebase-tools我们有一个 GitHub 操作,它使用(我们使用的是最新版本9.11.0)包将数据从一个 Firebase 项目复制到另一个项目:

firebase use fromProject && firebase database:get / -o export.json
firebase use toProject && firebase database:set -y / export.json

这一直很好,直到我们的数据变得更大,现在我们收到以下错误:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

作为临时修复,我们也能够应用节点--max-old-space-size标志,这只会增加节点进程可用的内存:

node --max-old-space-size=4096 /home/runner/work/foo/foo/node_modules/firebase database:set -y / export.json

考虑到我们的数据将不断增长,我们希望实施一个适当的修复,在我的理解中,这将是通过流式传输JSON 来设置数据。但是,我不确定是否firebase-tools允许这样做。搜索 Github 问题并没有产生任何有用的信息。

也许除了流式传输之外,还有另一种有用的方法可以在设置之前将巨大的 JSON 文件拆分成块?

谢谢!

4

1 回答 1

0

我们使用带有 Firebase HTTP API 的 HTTP 流来克服保存、本地修改和上传巨大(超过 256mb)JSON 文件的麻烦。

我们构建了一个函数来从一个项目的数据库到另一个项目的数据库的 HTTP 管道数据流:

async function copyFirebasePath(path, from, to) {
  // getAccessToken from https://firebase.google.com/docs/database/rest/auth
  const fromAccessToken = await getAccessToken(from.key)
  const toAccessToken = await getAccessToken(to.key)

  return new Promise((resolve, reject) => {
    let toRequest
    // create write request, but don’t start writing to it
    // we’ll pipe the read request as the data to write
    try {
      toRequest = https.request(
        `${to.databaseUrl}/${path}.json?print=silent`,
        {
          method: 'PUT',
          headers: {
            Authorization: `Bearer ${toAccessToken}`
          }
        },
        (/* res */) => {
          resolve()
        }
      )
    } catch (writeError) {
      reject(writeError)
    }

    try {
      https
        .request(
          `${from.databaseUrl}/${path}.json`,
          {
            method: 'GET',
            headers: {
              Authorization: `Bearer ${fromAccessToken}`
            }
          },
          res => {
            res.pipe(toRequest)
            res.on('end', () => {
              toRequest.end()
            })
          }
        )
        .end()
    } catch (readError) {
      reject(readError)
    }
  })
}

我们像这样使用它:

// get Object.keys from remote db
const shallowDB = await request({
  method: 'get',
  // note ?shallow=true here – prevents loading the whole db!
  url: `${from.databaseUrl}/.json?shallow=true`,
  options: {
    headers: {
      Authorization: `Bearer ${fromAccessToken}`
    }
  }
})
const dbKeys = Object.keys(shallowDB)
const keysToOmit = ['foo', 'bar', 'baz']

try {
  await Promise.all(
    dbKeys
      .filter(dbKey => !keysToOmit.includes(dbKey))
      .map(key => copyFirebasePath(key, from, to))
  )
} catch (copyError) {
  console.log(copyError)
  throw new Error(copyError)
}
于 2022-01-14T20:07:46.250 回答