Last active
December 7, 2023 15:33
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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