【问题标题】:How to import test data into Firebase Firestore emulator from production for easy testing?如何将测试数据从生产环境导入 Firebase Firestore 模拟器以便于测试?
【发布时间】:2020-06-07 19:39:50
【问题描述】:

我正在构建一个监听触发器并向用户发送推送通知的 firebase 函数。触发器基于 firestore 数据,对于我来说,每次在 firestore 模拟器上手动重新创建都太复杂了。

我尝试模拟函数,但连接到 Firestore 生产,但似乎在这种情况下,触发器函数不起作用????

我想要做的是从我的生产 Firestore 中导出我的数据,然后将其导入我的模拟器 Firestore,这样至少,我正在使用的副本非常接近我在 prod 上的内容;需要明确的是,数据很小,所以我不担心下载 TB 的数据。

我找到了way of importing data into an emulator,但不确定这是否适用于生产数据或如何从生产中转储数据。

firebase emulators:start --import=./some-directory

【问题讨论】:

  • 您将不得不为此编写代码。这不是简单的配置或命令行选项的问题。

标签: node.js firebase google-cloud-firestore firebase-tools


【解决方案1】:

您可以从生产环境手动导出,然后导入 Firestore 模拟器。

首先将生产数据导出到文件。在示例中,我仅在 onRequest 函数中导出“用户”集合,因此我可以通过调用 URL 来启动。注意,这个函数不会处理子集合。

exports.exportFirestore = functions.https.onRequest(async (req, res) => {
  const fs = require("fs");

  const collection = "users";
  const fileName = "fs-export.json";
  const exportedData = {};
  exportedData[collection] = {};

  await admin
    .firestore()
    .collection(collection)
    .get()
    .then((snapshot) => {
      return snapshot.forEach((doc) => {
        exportedData[collection][doc.id] = doc.data();
      });
    })
    .catch(console.error);

  fs.writeFile(fileName, JSON.stringify(exportedData), (err) => {
    if (err) {
      console.log(err);
    } else {
      console.log("Firestore Export Complete.");
      res.send("Firestore Export Complete.");
    }
  });
});

接下来,将文件导入本地 Firestore 模拟器。 非常重要:确保 Firestore 模拟器运行,否则您会将数据导入回 prod。请务必通过检查 Web UI 来检查 Firestore 是否正在运行:http://localhost:4000。使用以下命令启动模拟器:firebase emulators:start

exports.importFirestore = functions.https.onRequest(async (req, res) => {
  const fs = require("fs");

  let collection;
  const fileName = "fs-export.json";
  const exportedData = {};
  exportedData[collection] = {};

  fs.readFile(fileName, "utf8", async (err, data) => {
    if (err) {
      return console.log(err);
    }

    const arr = JSON.parse(data);

    const batch = admin.firestore().batch();

    for (let i in arr) {
      collection = i;
      for (let doc in arr[i]) {
        if (arr[i].hasOwnProperty(doc)) {
          const ref = admin.firestore().collection(collection).doc(doc);
          batch.set(ref, arr[i][doc]);
        } else {
          console.log("Missing:", JSON.stringify(doc, null, 2));
        }
      }
    }

    await batch
      .commit()
      .then(() => {
        return console.log("Import to Firestore Complete");
      })
      .catch(console.error);

    return res.send("Import to Firestore Complete");
  });
});

【讨论】:

  • 导出的文件存放在哪里?
【解决方案2】:

我的回答深受@Geoffrey Bourne 回答的启发,但我必须修改一些内容并找出更多细节才能使其发挥作用。

首先,我将exportFirestore 上传到 Cloud Functions(生产)。当我通过这个 URL https://us-central1-<project-id>.cloudfunctions.net/exportFirestore 运行它时,我会下载一个文件,因为 Cloud Functions 是 read-only

以下代码用于一个名为fl_content 的集合,我会考虑将其扩展到多个集合

export const exportFirestore = functions.https.onRequest(async (req, res) => {
    const collection = "fl_content";
    const exportedData: any = {};
    exportedData[collection] = {};

    await admin
        .firestore()
        .collection(collection)
        .get()
        .then((snapshot) => snapshot.forEach((doc) => exportedData[collection][doc.id] = doc.data()))
        .catch(console.error);

    const data = JSON.stringify(exportedData);
    res.setHeader('Content-disposition', 'attachment; filename=fire-export.json');
    res.setHeader('Content-type', 'application/json');
    res.write(data, function () {
        res.end();
    });
})

下载文件fire-export.json 后,将其放入functions 文件夹中。然后打开导入功能的 URL(本地)http://localhost:5001/<project-id>/us-central1/importFirestore。确保collection 变量在导出和导入中相同。

export const importFirestore = functions.https.onRequest(async (req, res) => {
    const fs = require("fs");
    const collection = "fl_content";
    const fileName = "fire-export.json";
    const exportedData: any = {};
    exportedData[collection] = {};

    fs.readFile(fileName, "utf8", async (err: any, data: any) => {
        if (err) {
            res.send(err);
            functions.logger.error(err)
            return;
        }
        const arr = JSON.parse(data);
        const batch = admin.firestore().batch();

        for (const i in arr) {
            for (const doc in arr[i]) {
                if (arr[i].hasOwnProperty(doc)) {
                    const ref = admin.firestore().collection(collection).doc(doc);
                    batch.set(ref, arr[i][doc]);
                } else {
                    functions.logger.error("Missing:", JSON.stringify(doc, null, 2));
                }
            }
        }

        await batch
            .commit()
            .then(() => console.log("Import to Firestore Complete"))
            .catch(console.error);

        res.send("Import to Firestore Complete");
    });
});

【讨论】:

    猜你喜欢
    • 2020-11-07
    • 1970-01-01
    • 2018-11-26
    • 2021-05-13
    • 2016-08-09
    • 2013-11-05
    • 1970-01-01
    • 2019-10-09
    • 2018-08-11
    相关资源
    最近更新 更多