How to Enforce Unique Field Values in Cloud Firestore

The Cloud Firestore is an awesome platform for quickly prototyping your app ideas into reality, however, it certainly comes with some limitations.

firestore-field-uniqueness

Currently, there is no way for you to enable uniqueness in field values in the whole database. There is a quick workaround, though with queries that you can use.

The Problem

You want to enforce uniqueness for a field value in your Firestore database for your app.

Use Case

An app where users have their profiles and a unique username assigned to them.

Natively, the Cloud Firestore provides us with no uniqueness check from either Rules or the SDK. But, of course, there is a workaround.

The Workaround

You can use Firestore queries to get the document ID which corresponds to the field you want to keep unique. If the query returns null, that would mean that the database doesn’t contain that value., ergo, the username, in this case, is available or vice versa.

Of course, you’d like to see some code sample, so let’s get to that.

Consider a sample Users collection with and a few child documents. Our database is set up such that each document corresponds to a single user profile data.

The uId is the doc ID of the document that contains these fields. We have three fields and in a database like this, we generally want to keep the usernameand email fields unique throughout the database.

/Users
    {uId}/
        name: "Papa Panda"
        username: "boredpanda"
        email: "[email protected]"
    {uId}/
        name: "Excited Panda"
        username: "excitedpanda"
        email: "[email protected]"
    ...
/...

To keep things simple, we will simply focus on keeping the username field unique in our database.

Here’s the code for the Javascript web SDK:

'use strict';

// ***** firebase stuff start *****
firebase.initializeApp({
    apiKey: '####',
    authDomain: '####',
    databaseURL: '####',
    projectId: '####',
 });
const db = firebase.firestore();
// ***** firebase stuff end *****

// reference to the Users root collection
const usersRootRef = db.collection('Users');

/* 
    make sure that you trim() and use toString() methods (if required)
    to ensure that the inputUsername only contains the exact
    string that you have stored in the database
    with no starting or ending spaces 
*/
const inputUsername = getUsernameFromInput();

/* 
    where() finds the document which has the 'username' 
    field matching the username input which you get from the user.
    It only accepts three strings as the arguments.
*/
const query = usersRootRef.where('username', '==', inputUsername).get();
let userDocId = undefined;

query.then(snapShot => {
        snapShot.map(doc => {
            userDocId = doc.id;
        });
        // userDocId will be undefined if query doesn't match
        // anything in the Firestore
        if(userDocId !== undefined) {
            // prompt the user to come up with something else
            console.log('username already taken');
        } else {
            // If there is no document in the Firestore with that 
            // username the resulting 'userDocId ' will be undefined.
            console.log('username available');
        }
    }).catch(error => {
        console.log(error);
    });
});

This code simply queries the Firebase’s Firestore usig the where() method to get the reference to the document which has the username field occupied with your inputUsername.value. You can then prompt your user to think of some new username since this one is already taken.

So, that’s how you can enforce uniqueness throughout the Firestore database on your app. The same logic can be applied to the email uniqueness issue too. You’ll need to change the query to something like the following depending on what field names you have used:

const query = usersRootRef.where('email', '==', getUserEmailFromInput()).get();

That’s all.

Leave a Reply

Your email address will not be published. Required fields are marked *