如何将数据从 Cloud Firestore 导入到本地模拟器?

Posted

技术标签:

【中文标题】如何将数据从 Cloud Firestore 导入到本地模拟器?【英文标题】:How to import data from cloud firestore to the local emulator? 【发布时间】:2020-01-10 07:41:44 【问题描述】:

我希望能够在本地运行云功能并针对生产数据的副本进行调试。 有没有办法将在线的数据复制到本地firestore模拟器?

【问题讨论】:

请不要导入您的生产数据库进行测试。当您这样做时,您可能会暴露所有客户的个人数据。相反,创建经过清理的暂存数据。 【参考方案1】:

这可以通过现有项目的终端中的一组命令来完成:

1.登录 firebase 和 Gcloud:

firebase login
gcloud auth login

2。查看您的项目列表并连接到一个:

firebase projects:list
firebase use your-project-name

gcloud projects list
gcloud config set project your-project-name

3。使用所选名称将您的生产数据导出到 gcloud 存储桶:

gcloud firestore export gs://your-project-name.appspot.com/your-choosen-folder-name

4.现在将此文件夹复制到您的本地计算机,我直接在函数文件夹中执行此操作:

cd functions
gsutil -m cp -r gs://your-project-name.appspot.com/your-choosen-folder-name .

5.现在我们只想导入这个文件夹。这应该与基本命令一起使用,感谢 Firebase 团队的最新更新 https://github.com/firebase/firebase-tools/pull/2519.

firebase emulators:start --import ./your-choosen-folder-name

查看我在 Medium 上关于它的文章以及为您完成这项工作的简写脚本https://medium.com/firebase-developers/how-to-import-production-data-from-cloud-firestore-to-the-local-emulator-e82ae1c6ed8

注意:最好为它使用不同的存储桶,因为复制到您的项目存储桶中会导致在您的 Firebase 存储中创建文件夹。 如果您对 -m 这样的 gsutil 参数感兴趣,您可以通过执行 gsutil --help 来查看它们的描述。

【讨论】:

当我导入数据时,它需要的时间超过 30000 毫秒,因此模拟器无法运行。有没有办法解决这个超时? 你的意思是你在运行这个命令时出错:firebase emulators:start --import your-choosen-folder-name ?你能分享错误信息吗?只是想看看 firebase 是在抛出超时还是我们可以增加的某种内部超时。 快速注意,当前运行 python 3.8 时 gsuit 存在一个错误。使用 -m 标志会使它崩溃,您可以使用 python 3.7 运行它,也可以不使用标志 -m 运行。 更新了更短的版本,不再需要元数据重命名,请参阅:github.com/firebase/firebase-tools/pull/2519。 确保在开始之前安装 Google Cloud SDK (cloud.google.com/sdk/docs/install) 和 Firebase CLI (firebase.google.com/docs/cli)。【参考方案2】:

我的方法有点手动,但确实有效。我已经在this useful Github thread 中分享了它,但如果你觉得它们有用,我会在这里列出我所做的步骤:

    转到我的本地 Firebase 项目路径。 使用以下命令启动模拟器:firebase emulators:start 使用http://localhost:4000/firestore 的 GUI 使用提供的按钮手动创建一些模型数据:+ Start Collection+ Add Document。 在本地导出此数据,使用: emulators:export ./mydirectory 关于位于 Firebase 数据库/Cloud Firestore 的项目数据,我导出了一个这样的集合:gcloud firestore export gs://my-project-bucket-id.appspot.com --collection-ids=myCollection 现在导出位于 Firebase Storage 下以时间戳为名称的文件夹(我的测试没有使用前缀) 将此文件夹下载到本地驱动器:gsutil cp -r gs://my-project-bucket-id.appspot.com/myCollection ./production_data_export 注意:我是在 Windows 环境中执行此操作的... gsutil 将抛出此错误:"OSError: The filename, directory name , 或卷标语法不正确” 如果该文件夹在 Windows 中包含无效的文件夹名称字符(即冒号)或此错误:“OSError: Invalid argument.9.0 B]” 如果文件夹中的内部文件也包含无效字符。为了能够在本地下载导出文件,请使用有效的 Windows 名称重命名它们(即删除冒号),如下所示:gsutil mv gs://my-project-bucket-id.appspot.com/2020-05-22T02:01:06_86152 gs://my-project-bucket-id.appspot.com/myCollection 下载后,模仿本地导出结构将文件夹重命名为firestore_export 并从本地导出文件夹中复制firebase-export-metadata.json 文件。只是为了直观,这是我得到的结构:
$ tree .
.
├── local_data_export
│   ├── firebase-export-metadata.json
│   └── firestore_export
│       ├── all_namespaces
│       │   └── all_kinds
│       │       ├── all_namespaces_all_kinds.export_metadata
│       │       └── output-0
│       └── firestore_export.overall_export_metadata
└── production_data_export
    ├── firebase-export-metadata.json
    └── firestore_export
        ├── all_namespaces
        │   └── kind_myCollection
        │       ├── all_namespaces_kind_myCollection.export_metadata
        │       ├── output-0
        │       └── output-1
        └── firestore_export.overall_export_metadata

8 directories, 9 files
    最后,启动本地模拟器指向这个要导入的生产数据:firebase emulators:start --import=./mock_up_data/production_data_export/ 您应该会在以下位置看到导入的数据:http://localhost:4000/firestore/

这应该对读者有所帮助,同时我们等待 Firebase 人员提供更强大的解决方案。

【讨论】:

这确实有效!我遇到的唯一怪癖是导出 Firestore——它不会导出我的收藏内容——只是一个空的收藏。我放弃了 -collection-ids 标志,只是导出了所有内容,它工作了 如果没有验证用户数据,只导出数据库可能毫无用处。为此,请在本地项目终端中使用:% firebase auth:export accounts.json --format=json。另见:firebase.google.com/docs/cli/auth 小注:在步骤#4中,整个命令为firebase emulators:export ./mydirectory。我知道这很明显,但我确实困惑了一分钟。【参考方案3】:

您可以使用firestore-backup-restore 将生产数据导出和导入为 JSON 文件。

我写了一个快速技巧来允许在 Firebase Simulator Firestore 实例中导入这些 JSON。

我提出了一个拉取请求,同时提出了这个npm module。

你可以这样使用它:

const firestoreService = require('@crapougnax/firestore-export-import')
const path = require('path')

// list of JSON files generated with the export service
// Must be in the same folder as this script
const collections = ['languages', 'roles']

// Start your firestore emulator for (at least) firestore
// firebase emulators:start --only firestore

// Initiate Firebase Test App
const db = firestoreService.initializeTestApp('test', 
   uid: 'john',
   email: 'john@doe.com',
)

// Start importing your data
let promises = []
try 
   collections.map(collection =>
      promises.push(
         firestoreService.fixtures(
            path.resolve(__dirname, `./$collection.json`),
            [],
            [],
            db,
         ),
      ),
   )
   Promise.all(promises).then(process.exit)
 catch (err) 
   console.error(err)

显然,由于这些数据不会保留在模拟器中,因此您通常会将它们注入测试套件的 before() 函数中,甚至在每次测试之前。

【讨论】:

我无法让 fireestoer-export-import 工作,因为它似乎有一些过时的依赖项,并且在全局安装以使用 \bin 中的脚本或尝试构建克隆的 repo 时失败在窗户上。 跟进;克隆旧的仓库;按照 cmets 的建议,删除 package.json 中对 @google-cloud/firestore 的引用;我可以用npm run build 构建它,然后用node ./build/index.js 导出信息。【参考方案4】:

没有将数据从云项目复制到本地模拟器的内置方法。由于模拟器不保留任何数据,因此您必须在每次运行时重新生成初始数据集。

【讨论】:

【参考方案5】:

我能够制作一些 npm 脚本以从远程导入到本地模拟器,反之亦然。

"serve": "yarn build && firebase emulators:start --only functions,firestore --import=./firestore_export",
"db:update-local-from-remote": "yarn db:backup-remote && gsutil -m cp -r gs://my-firebase-bucket.appspot.com/firestore_export .",
"db:update-remote-from-local": "yarn db:backup-local && yarn db:backup-remote && gsutil -m cp -r ./firestore_export gs://my-firebase-bucket.appspot.com && yarn run db:import-remote",
"db:import-remote": "gcloud firestore import gs://my-firebase-bucket.appspot.com/firestore_export",
"db:backup-local": "firebase emulators:export --force .",
"db:rename-remote-backup-folder": "gsutil mv gs://my-firebase-bucket.appspot.com/firestore_export gs://my-firebase-bucket.appspot.com/firestore_export_$(date +%d-%m-%Y-%H-%M)",
"db:backup-remote": "yarn db:rename-remote-backup-folder && gcloud firestore export gs://my-firebase-bucket.appspot.com/firestore_export"

因此您可以使用以下方式将本地 Firestore 数据导出到远程:

npm db:update-remote-from-local

或者要使用远程更新本地 Firestore 数据,请执行以下操作:

npm db:update-local-from-remote

这些操作将备份远程 Firestore 数据,制作副本并将其存储在 Firebase 存储中。

【讨论】:

"db:update-local-from-remote": "yarn db:backup-remote && gsutil -m cp -r gs://my-firebase-bucket.appspot.com/firestore_export 。 ", 这个如何导入到模拟器数据库? 抱歉,命令列表缺少“serve”命令,该命令使用 --import 选项启动模拟器。因此,在运行db:update-local-from-remote 之后,您只需要重新启动您的模拟器。 github.com/firebase/firebase-tools/pull/1968 我们如何运行 db:update-local-from-remote 脚本?这是否意味着从 gcloud、firebase 或其他程序运行? 从您的本地环境发送给您 因为这个文件而失败:firebase-export-metadata.json【参考方案6】:

我正准备向firebase-tools 添加一个cli 选项,但对node-firestore-import-export 包非常满意。

yarn add -D node-firestore-import-export
  "scripts": 
    "db:export": "firestore-export -a ./serviceAccountKey.json -b ./data/firestore.json",
    "db:import": "firestore-import -a ./serviceAccountKey.json -b ./data/firestore.json",
    "db:emulator:export": "export FIRESTORE_EMULATOR_HOST=localhost:8080 && yarn db:export",
    "db:emulator:import": "export FIRESTORE_EMULATOR_HOST=localhost:8080 && yarn db:import",
    "db:backup": "cp ./data/firestore.json ./data/firestore-$(date +%d-%m-%Y-%H-%M).json",
    "dev": "firebase emulators:start --import=./data --export-on-exit=./data",
  ,

您需要在 Firebase 控制台中创建一个服务帐号。

您可以将GCLOUD_PROJECT 环境变量替换为硬编码值。

open https://console.firebase.google.com/project/$GCLOUD_PROJECT/settings/serviceaccounts/adminsdk
mv ~/Downloads/myProjectHecticKeyName.json ./serviceAccountKey.json

话虽如此,gcloud 工具绝对是生产环境的最佳选择,因为无论如何您都需要 s3 备份。

【讨论】:

【参考方案7】:

我写了一个小脚本来做到这一点:

const db = admin.firestore();
const collections = ['albums', 'artists'];
let rawData: any;
    
for (const i in collections) 
    rawData = fs.readFileSync(`./$collections[i].json`);
    const arr = JSON.parse(rawData);

    for (const j in arr) 
        db.collection(collections[i]).add(arr[j])
        .then(val => console.log(val))
        .catch(err => console.log('ERRO: ', err))
    
        

【讨论】:

以上是关于如何将数据从 Cloud Firestore 导入到本地模拟器?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 CSV 或 JSON 导入到 Firebase Cloud Firestore

如何使用 Cloud Function 将数据从 Firebase Firestore 索引到 Elastic App Search?

如何将新数据从实时数据库推送到 Cloud Firestore?

Cloud Firestore:从 API 添加和更新数据

如何将我的 Firebase 实时数据库转移到 Firebase Cloud Firestore

如何将我的 Firebase 实时数据库转移到 Firebase Cloud Firestore