Reputation: 9151
I'm searching for a way to add pre-deployment scripts to my Firebase project.
I'm using Firestore and my security rules are set up in a way that only cloud functions can write to Firestore.
I've added a user role field to my user table which automatically gets populated on userCreate. This works fine but my prod env still has users without this field.
A logical solution would be to run a pre-deploy command which add this field to all existing users but I have no clue how to do this.
My current best solution is to create a cloud function specifically for this one-time use and trigger it.
This doesn't feel like the right way to handle such things.
How do I run a one time update statement on Firestore?
Upvotes: 0
Views: 168
Reputation: 9151
I've updated @Dharmaraj answer with some extra features in case someone ever needs this.
const admin = require('firebase-admin');
// DEV
const serviceAccount = require('./x-dev-firebase-adminsdk-1234.json');
// PROD
// const serviceAccount = require('./x-firebase-adminsdk-1234.json');
const newRoles = [0];
const emails = ['[email protected]', '[email protected]'];
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
const addRoles = async () => {
try {
let userColRef = admin.firestore().collection('users');
if (emails.length) {
userColRef = userColRef.where('email', 'in', emails);
}
const users = await userColRef.get();
const updates = [];
users.docs.forEach((doc) => {
const user = doc.data();
let existingRoles = [];
if (user.roles) {
existingRoles = user.roles;
if (newRoles.every((role) => existingRoles.includes(role))) {
return;
}
}
const roles = Array.from(new Set(existingRoles.concat(newRoles)));
updates.push(doc.ref.set({ roles }, { merge: true }));
});
await Promise.all(updates);
console.log(
`Role${newRoles.length > 1 ? 's' : ''} added to ${updates.length} user${
updates.length !== 1 ? 's' : ''
}.`
);
return true;
} catch (error) {
console.log(error);
return error;
}
};
addRoles().catch((e) => {
console.log(e);
});
Here's where you create the service account btw.
Upvotes: 0
Reputation: 50920
You can write a temporary script using Firebase Admin SDK and execute it once. The flow would look something like:
Here's a demo:
const admin = require("firebase-admin");
const serviceAccount = require("/path/to/serviceAccountKet.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://fate-bot-discord.firebaseio.com"
});
async function addRoles() {
try {
const userColRef = admin.firestore().collection("users")
const users = await userColRef.where("userRole", "==", "").get()
const updates = []
users.docs.forEach((user) => {
updates.push(userColRef.doc(user.id).update({ userRole: "theNewRole" }))
})
await Promise.all(updates)
console.log("Roles added successfully")
return "Roles Added"
} catch (error) {
console.log(error);
return error
}
}
//Call the function
addRoles().then((response) => {
console.log(response)
}).catch((e) => {
console.log(e)
})
Please let me know if you need further assistance!
Upvotes: 1