firebasegoogle-cloud-firestore

Whats the process for updating existing user data in Firestore when a new feature requires data to be added/different?


I've found several other posts asking similar questions but they all have a specific code element to them and this question is much more on process or best practice with regards to Firebase and NOSQL databases. I'll be able to figure out the code once I know what direction I should take.

Context

I have a simple app that uses React and a Firestore database. It's been deployed and currently has 1 user... me. But lets for the sake of this question imagine I have 1000 users. Each user can create any number of 'items' or 'views' and has some data stored in a 'user' document.

I've gone ahead and created a new feature for my app that requires:

  1. A new field to be present in the user document
  2. An existing field needs to be renamed (renamed for clarity in the code)

As I'm the only user I could just trash the Firestore and start again but my other 999 imaginary users might be a little annoyed that their data has been deleted so...

What's the correct way to handle this? From reading various posts there seems to be three ways but I'm not sure which is best practice.

Possible solutions

  1. Run some kind of script using cloud functions?? that manipulates the existing data so it's ready for the new release.

This is my preferred solution as it's a one and done exercise but I don't know how this works in Firestore. I'm not 100% sure of the relationship between Firebase and Google Cloud or how to actually do this.

  1. Account for the possible differences in data within the app but include functions which will correct and update the document.

This seems messy because as the app grows and I encounter this problem again I'll forever need more complex code to handle the different versions and this introduces more chance of bugs or other issues.

  1. Create my own 'admin' app and write functions which will manipulate the data as this can't be done natively in the Firebase Console. Seems reasonable but I'm not sure why this can't be done in the console. Is this my best route?

Or is there something else I've missed entirely?

Please send help.


Solution

  • Mess in data - it's a problem which can become in FB due to it's NoSQL nature. You can utilize FB rules to ensure your data is always written in the right format you expect. (Although we would welcome a native schema support)

    When you want to do changes:

    1. As you describe, we run script which we call "migrations". Which transforms the data to a correct format. This doesn't need to be run trough Cloud Function. It can be simple script with node. Ideally you integrate this in CI/CD pipeline.
    import admin from "firebase-admin";
    
    // TODO in project settings > Service accounts > Generate new private key
    import serviceAccount from "./path/to/serviceAccountKey.json";
    
    admin.initializeApp({
      credential: admin.credential.cert(serviceAccount),
      // TODO change to your DB url
      databaseURL: "https://xxxx.firebaseio.com",
    });
    
    const migrate = async () => {
      const docs = await admin.firestore().collection("workspaces").listDocuments();
      console.log("Going to process number of WS:", docs.length);
      ...
      console.log("Successfully processed number of users:", counter);
      }
    };
    
    migrate().then(() => console.log("Migration done"));
    
    1. I would advise from counting in the app with different states. We sometimes do it but we try to avoid it as much as possible and ensure the correct state with rules, migrations and typescript.

    2. Firebase console is not the best way to manipulate data. We have been using these 2 tools: