首页 > 解决方案 > 同时连接到 Firestore 在线和模拟器?

问题描述

我想编写一个 CLI 脚本,将一些数据从我们的实时应用程序复制到本地 Firestore 模拟器,用于开发和测试目的。

文档说您应该设置环境变量以FIRESTORE_EMULATOR_HOST连接到本地模拟器——但这不允许同一个应用程序也连接到服务器。

我试过这个:

const onlineApp = await admin.initializeApp(
    {
      credential: admin.credential.applicationDefault(),
      databaseURL: 'https://....firebaseio.com',
    },
    'default'
  );

process.env['FIRESTORE_EMULATOR_HOST'] = 'localhost:8080';

const emulator = await admin.initializeApp(
    {
      projectId: 'emulator',
    },
    'emulator'
  );

...但随后onlineApp不再与在线 Firestore 对话。

是否有另一种方法可以做到这一点,以便我可以同时创建与两者的连接?

标签: node.jsfirebasegoogle-cloud-firestorefirebase-admin

解决方案


经过一些试验和错误后,似乎可以同时连接到两者。下面的代码首先连接到真实的 Firestore 数据库并进行所需的文档读取,然后实例化第二个客户端以与 Firestore 模拟器对话并进行写入。

const admin = require('firebase-admin');
const serviceAccount = require('./key.json');

const f1 = async () => {
    const onlineApp = admin.initializeApp(
        {
            project: "PROJECT_ID",
            credential: admin.credential.cert(serviceAccount)
        },
        'default'
    );
    const onlineFirestore = onlineApp.firestore()
    const ondoc = await onlineFirestore.collection("XXX").doc("YYY").get()
        .then((doc) => {
            console.log(doc.data())
            return doc.data()
        });
    // Retrieve whatever needed here
}

const f2 = async () => {
    const emulator = admin.initializeApp(
        {
            project: "PROJECT_ID",
            credential: admin.credential.cert(serviceAccount)
        },
        'emulator'
    );
    process.env['FIRESTORE_EMULATOR_HOST'] = 'localhost:8080';
    const emulatorFirestore = emulator.firestore()
    await emulatorFirestore.collection("XXX").doc("YYY").set({some:"thing").then((res) => console.log(res));
}

const flow = async () => {
    await f1();
    await f2();
}

flow()

我无法确切解释为什么上面的代码有效(如果我发现更多,我会更新答案)。尽管如此,我还是想提一些事情。

  • Firestore 客户端会自动读取环境变量FIRESTORE_EMULATOR_HOST。似乎您可以通过在设置环境变量之前进行读取来强制第一个连接到在线。
  • 如果FIRESTORE_EMULATOR_HOST在执行脚本之前已经在系统中设置了它,它就会失败。和以前一样,客户端自己读取它,使 onlineApp 连接到模拟器。为防止这种情况发生,请确保在脚本运行之前停止重新启动模拟器。
  • 由于上述原因,所有异步/等待的东西都在那里强制评估顺序。

综上所述,我宁愿建议导出生产 Firestore 实例并在模拟器中使用它,这似乎更可靠。另外,请记住,模拟器具有导入/导出功能,允许在模拟器运行期间保留数据库状态,因此可能更容易设置一次数据(手动或从普通 JS 对象)并将其导出。


推荐阅读