After some trial and error it seems to be possible to connect to both simultaneously. The code below connects first to the real Firestore database and makes the document reads needed, then instantiates a second client to talk with the Firestore emulator and make the writes.
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()
I'm unable to explain exactly why the code above works (I'll update the answer if I find out more). Nonetheless here are some things I'd like to mention.
- The Firestore client automatically reads the environment variable
FIRESTORE_EMULATOR_HOST
. It seems that you can force the first to connect to the online one by making a read before setting the environment variable.
- If the
FIRESTORE_EMULATOR_HOST
is already set in the system before executing the script it just fails. As before, the client reads it by itself which makes the onlineApp connect to the emulator. To prevent so, make sure to stop-restart the emulators before the script runs.
- All the async/await stuff is there to force the evaluation order for the reasons mentioned above.
All that said, I would rather suggest to make an export of the production Firestore instance and use it in the emulator, which seems more reliable. Also, keep in mind that the emulator has an import/export functionality which allows to preserve the database state across emulator runs, thus it may be easier to set up the data once (manually or from plain JS objects) and export it.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…