如何从生产中将测试数据导入Firebase Firestore模拟器以进行简单测试?

时间:2020-06-07 19:39:50

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

我正在构建一个Firebase函数,该函数可侦听触发器并将推送通知发送给用户。触发器基于Firestore数据,对于我来说,它太复杂,以至于每次都无法在Firestore模拟器上手动重新创建。

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

我想要做的是从生产Firestore中导出数据,然后将其导入到仿真器Firestore中,这样至少,我正在使用的副本与我生产的产品非常相似;显然,数据很小,所以我不必担心下载TB级的数据。

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

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

2 个答案:

答案 0 :(得分:3)

您可以从生产中手动导出,然后导入到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模拟器,否则您将数据导入回产品中。确保通过检查以下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");
  });
});

答案 1 :(得分:0)

我的答案在很大程度上受到@Geoffrey Bourne答案的启发,但我不得不修改一些内容并找出更多细节才能使它起作用。

首先,我将exportFirestore上传到Cloud Functions(生产)。当我通过此URL https://us-central1-<project-id>.cloudfunctions.net/exportFirestore运行它时,由于云功能为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");
    });
});