Last active
September 10, 2023 02:18
-
-
Save gregfenton/fb9b3aeede570964b84fe6129a463561 to your computer and use it in GitHub Desktop.
Deletes all records from a Firestore collection that match some criteria -- 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
/** | |
* cleanup_firestore.js | |
* | |
* This code is a "node script" used to delete all documents from a Firestore | |
* collection that are older than a given date. This script can run against | |
* "the cloud" or the emulator. | |
* | |
* The jump point for the script is this line in main(): | |
* | |
* await deleteDocs('orders', 'closedDate', '<', new Date('2021/08/31')) | |
* | |
* where `orders` is the collection and `closedDate` is a field in each document. | |
* | |
* The script is a "client app", so it logs in with Firebase Auth using email/password from the variable USER1. | |
* This USER1 user ([email protected]) must exist in your Firebase project and have write access | |
* to the collection you are deleting from. You can create that user account via | |
* Firebase Console >> Authentication. | |
* | |
* 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 `deleteDocs()`. | |
* | |
* NOTE: this code works with the Firebase Web SDK v9 API. Earlier revisions used the v8 API. | |
* | |
* To run: node cleanup_firestore.js | |
* | |
* Alternatively, you can create a "script" in package.json: | |
* "scripts": { | |
* ... | |
* "cleanup": "node tools/cleanup/cleanup_firestore.js" | |
* } | |
* | |
* and then run the script with: npm run cleanup | |
*/ | |
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 () => { | |
let fbApp = initializeApp(FIREBASE_CONFIG); | |
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" | |
// }, | |
// ... | |
// | |
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 deleteDocs = async (collectionPath, field, compareOp, compareValue) => { | |
let queryRef = query( | |
collection(FIRESTORE, collectionPath), | |
where(field, compareOp, compareValue) | |
); | |
let querySnap = getDocs(queryRef); | |
console.log(`WHERE returned ${querySnap.size} records`); | |
let batch = writeBatch(FIRESTORE); | |
querySnap.forEach((docSnap) => { | |
console.log(`DELETING ${docSnap.ref.id}`); | |
batch.delete(docSnap.ref); | |
}); | |
try { | |
await batch.commit(); | |
console.log('Transaction successfully committed!'); | |
} catch (ex) { | |
console.log(`Transaction failed: ${ex.message}`); | |
throw ex; | |
} | |
}; | |
const main = async () => { | |
console.log('>>> START LOADING Users - ', Date()); | |
await initializeFB(); | |
await deleteDocs('orders', 'closedDate', '<', new Date('2021/08/31')); | |
console.log('>>> DONE - ', Date()); | |
process.exit(0); | |
}; | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment