Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gregfenton/37a9c9526783119429d49e78dd361610 to your computer and use it in GitHub Desktop.
Save gregfenton/37a9c9526783119429d49e78dd361610 to your computer and use it in GitHub Desktop.
Updates all docs in a Firestore collection with the given values -- command-line JavaScript/node
/**
* firestore_add_field_to_all_docs_in_collection.js
*
* This script is assumed to live in an existing Javascript project that has its own package.json.
* I store this script in <PROJECT_ROOT>/tools/cleanup/.
*
* To use:
* 1. Import the 'firebase' and 'esm' NPM modules to your project (Run the command: `npm install firebase esm`)
* 2. Edit the data for USER1 and FIREBASE_CONFIG, then adjust parameters in `main` for the call to `visitDocs`.
*
* NOTE: this code works with the Firebase Web SDK v9 API. Earlier revisions used the v8 API.
*
* To run: node firestore_add_field_to_all_docs_in_collection.js
*
* Alternatively, you can create a "script" in package.json:
* "scripts": {
* ...
* "add_field_to_fs": "node tools/cleanup/firestore_add_field_to_all_docs_in_collection.js"
* }
*
* and then run the script with: npm run firestore_add_field_to_all_docs_in_collection.js
*/
import {initializeApp} from 'firebase/app';
import {
addDoc,
collection,
connectFirestoreEmulator,
getFirestore,
writeBatch
} from 'firebase/firestore';
import {getAuth, signInWithEmailAndPassword} from 'firebase/auth';
let FIRESTORE;
let AUTH;
// Firebase Console >> Authentication
const USER1 = {
email: '[email protected]', // USER THAT EXISTS IN FIREBASE AUTH
password: 'let_me_in',
uid: UID_FROM_FIREBASE_AUTH_FOR_THIS_USER
};
// Firebase Console >> Project Overview >> General >> Apps
// (use existing app values or click Add app to create new WEB app)
const FIREBASE_CONFIG = {
apiKey: VALUES_FROM_FIREBASE_APP_CONFIG,
appId: VALUES_FROM_FIREBASE_APP_CONFIG,
authDomain: VALUES_FROM_FIREBASE_APP_CONFIG,
databaseURL: VALUES_FROM_FIREBASE_APP_CONFIG,
messagingSenderId: VALUES_FROM_FIREBASE_APP_CONFIG,
projectId: VALUES_FROM_FIREBASE_APP_CONFIG
};
const initializeFB = async () => {
// USE YOUR FIREBASE PROJECT SETTINGS:
// Firebase Console >> Project Overview >> Apps
// >> (select or "Add App" web app) >> Config
const firebaseConfig = {
apiKey: 'xxx',
appId: 'xxx',
authDomain: 'xxx',
databaseURL: 'xxx', // use project value for cloud, or use emulator values such as "http://192.168.1.53:5001/" (see USE_FIREBASE_EMULATOR below)
messagingSenderId: 'xxx',
projectId: 'xxx'
};
let fbApp = initializeApp(firebaseConfig);
FIRESTORE = getFirestore(fbApp);
let USING_FIREBASE_EMULATOR = true;
if (USING_FIREBASE_EMULATOR) {
// I explicitly set "host" and "port" in firebase.json so that devices
// on my local network can access the emulator:
// "emulators": {
// "functions": {
// "port": 5001,
// "host": "192.168.1.53"
// },
// "firestore": {
// "port": 5002,
// "host": "192.168.1.53"
// },
// ...
// or you could set host to "0.0.0.0" to enable all interfaces on your machine.
//
connectFirestoreEmulator(FIRESTORE, '192.168.1.53', 5002);
}
try {
AUTH = getAuth();
await signInWithEmailAndPassword(AUTH, USER1.email, USER1.password);
let currUser = AUTH.currentUser;
console.log(`Logged in with USER1 uid(${currUser.uid})`);
} catch (ex) {
console.error(ex.message);
throw ex;
}
};
const visitDocs = async (
collectionPath,
field = null,
compareOp = null,
compareValue = null,
updateValue
) => {
let collRef = collection(FIRESTORE, collectionPath);
if (field && compareOp) {
collRef = query(collRef, where(field, compareOp, compareValue));
}
let querySnap = getDocs(collRef);
console.log(`WHERE returned ${querySnap.size} records`);
let batch = writeBatch(FIRESTORE);
querySnap.forEach((docSnap, index) => {
console.log(
`UPDATING ${docSnap.ref.id} with: ${JSON.stringify(updateValue)}`
);
batch.update(docSnap.ref, updateValue);
// writeBatch is limited to 500 operations, so commit every 500 updates
if (index % 500 === 0) {
console.log(`Committing batch at index ${index}`);
batch.commit();
batch = writeBatch(FIRESTORE);
}
});
try {
await batch.commit();
console.log('Transaction successfully committed!');
} catch (ex) {
console.log(`Transaction failed: ${ex}`);
throw ex;
}
};
const main = async () => {
console.log('>>> START LOADING Users - ', Date());
await initializeFB();
// add/set an "enabled" field to true for all docs in the 'users' collection
await visitDocs('users', null, null, null, {enabled: true});
console.log('>>> DONE - ', Date());
process.exit();
};
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment