简体   繁体   English

如何将测试数据从生产中导入 Firebase Firestore 模拟器以便于测试?

[英]How to import test data into Firebase Firestore emulator from production for easy testing?

I am building a firebase function that listens to a trigger and sends a push notification to users.我正在构建一个 firebase function 来监听触发器并向用户发送推送通知。 The trigger is based on firestore data that's too complex for me to manually re-recreate every time on firestore emulator.触发器基于对我来说太复杂的 firestore 数据,无法每次在 firestore 模拟器上手动重新创建。

I tried emulating functions, but hooking up to firestore production, but seems like in this case, trigger functions don't work我尝试模拟功能,但连接到 Firestore 生产,但似乎在这种情况下,触发功能不起作用

What I want to do is export my data from my production Firestore then import it into my emulator firestore, so that at least, the copy I am working with is closely mimicking what I have on prod;我想要做的是从我的生产 Firestore 中导出我的数据,然后将其导入到我的模拟器 Firestore 中,这样至少,我正在使用的副本非常模仿我在 prod 上的内容; to be clear, the data is small, so I am not worried about downloading terabytes of data.需要明确的是,数据很小,所以我不担心下载 TB 的数据。

I found a way of importing data into an emulator , but not sure if this would work with production data or how I would dump the data from production.我找到了一种将数据导入模拟器的方法,但不确定这是否适用于生产数据或如何从生产中转储数据。

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

You can manually export from Production and then import into the Firestore emulator.您可以从 Production 手动导出,然后导入 Firestore 模拟器。

Start by doing an export of your production data to a file.首先将生产数据导出到文件。 In the example, I export just the "users" collection within an onRequest function so I can kick-off by calling the URL.在示例中,我仅导出 onRequest function 中的“用户”集合,因此我可以通过调用 URL 来启动。 Note, this this function will not handle subcollections.注意,这个 function 不会处理子集合。

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.");
    }
  });
});

Next, import the file into the local Firestore emulator.接下来,将文件导入本地 Firestore 模拟器。 Very important: be sure to have the Firestore emulator running otherwise you'll be importing your data back to prod.非常重要:确保运行 Firestore 模拟器,否则您会将数据导入回产品。 Be sure to check that Firestore is running by checking the web UI: http://localhost:4000 .请务必通过检查 web UI: http://localhost:4000来检查 Firestore 是否正在运行。 Start the emulator with: firebase emulators:start使用以下命令启动仿真器: 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");
  });
});

My answer is heavily inspired by @Geoffrey Bourne's answer, but I had to modify some stuff and figure out more details to get it working.我的回答深受@Geoffrey Bourne 回答的启发,但我必须修改一些内容并找出更多细节才能使其正常工作。

First, I upload the exportFirestore to Cloud Functions (production).首先,我将exportFirestore上传到 Cloud Functions(生产)。 When I run it through this URL https://us-central1-<project-id>.cloudfunctions.net/exportFirestore , I get a file DOWNLOADED, as Cloud Functions are read-only当我通过这个 URL https://us-central1-<project-id>.cloudfunctions.net/exportFirestore运行它时,我下载了一个文件,因为 Cloud Functions 是read-only

The below code is for one collection named fl_content , I'll consider expanding it to multiple collections下面的代码是一个名为fl_content的集合,我会考虑将它扩展到多个 collections

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();
    });
})

Once you have the file fire-export.json downloaded, put it inside the functions folder.下载文件fire-export.json ,将其放在functions文件夹中。 Then open the URL for the import function (locally) http://localhost:5001/<project-id>/us-central1/importFirestore .然后打开 URL 用于导入 function(本地) http://localhost:5001/<project-id>/us-central1/importFirestore Make sure the collection variable is the same in the export and import.确保导出和导入中的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");
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我在使用模拟器执行测试时仍然从生产中获取 Firestore 数据? - why I am still getting firestore data from production when performing testing using emulator? 如何设置用于单元测试的测试套件 Firebase 与模拟器连接的功能,特别是 Firestore 模拟器? - How to setup a test suit for unit testing Firebase Functions that connect with emulators, specifically the Firestore emulator? Firebase Firestore 模拟器如何工作? - How does Firebase Firestore emulator work? 如何让firebase function模拟器使用生产firebase存储桶 - How to let firebase function emulator use production firebase storage bucket 如何使用 Firebase 模拟器测试云功能 - How to test cloud function using firebase emulator 如何从json导入其他语言数据到Firestore? - How to Import other language data to Firestore from json? 如何使用 firebase function 从 firestore 检索文档并从另一个 firestore 文档添加新数据? - How to retrieve a document from firestore using firebase function and add new data from another firestore document? Cloud Firestore 模拟器未运行,因此调用 Firestore 会影响生产 - The Cloud Firestore emulator is not running, so calls to Firestore will affect production 从云中的 Firebase Firestore 获取数据 Function - Get Data from Firebase Firestore in Cloud Function 测试时连接firebase模拟器 - Connect to firebase emulator during test
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM