Firebase database: Referencing a dynamic value
<p>Lets assume I'm trying to build a group messaging application, so I designed my database structure to look like so:</p>

<pre><code>users: {
    uid1: { //A user id using push()
        username: "user1"
        email: "aaa@bbb.ccc"
        timestampJoined: 18594659346
        groups: {
            gid1: true,
            gid3: true
        }
    }
    uid2: {
        username: "user2"
        email: "ddd@eee.fff"
        timestampJoined: 34598263402
        groups: {
            gid1: true,
            gid5: true
        }
    }
    ....
}

groups: {
    gid1: { //A group id using push()
        name: "group1"
        users: {
            uid1: true,
            uid2: true
        }
    }
    gid2: {
        name: "group2"
        users: {
            uid5: true,
            uid7: true,
            uid80: true
        }
    }
    ...
}

messages: {
    gid1: {
        mid1: {  //A message id using push()
            sender: uid1
            message: "hello"
            timestamp: 12839617675
        }
        mid2: {
            sender: uid2
            message: "welcome"
            timestamp: 39653027465
        }
        ...
    }
    ...
}
</code></pre>

<p>According to Firebase's docs this would scale great.</p>

<p>Now lets assume that inside my application, I want to display the sender's username on every message.</p>

<p>Querying the username for every single message is obviously bad, so one of the solutions that I found was to duplicate the username in every message.</p>

<p>The messages node will now look like so:</p>

<pre><code>messages: {
    gid1: {
        mid1: {  //A message id using push()
            sender: uid1
            username: "user1"
            message: "hello"
            timestamp: 12839617675
        }
        mid2: {
            sender: uid2
            username: "user2"
            message: "welcome"
            timestamp: 39653027465
        }
        ...
    }
    ...
}
</code></pre>

<p>Now I want to add the option for the user to change his username.</p>

<p>So if a user decides to change his username, it has to be updated in the users node, and in every single message that he ever sent.</p>

<p>If I would have gone with the "listener for every message" approach, then changing the username would have been easy, because I would have needed to change the name in a single location.</p>

<p>Now, I have to also update the name in every message of every group that he sent.</p>

<p>I assume that querying the entire messages node for the user id is a bad design, so I thought about creating another node that stores the locations of all the messages that a user has sent.</p>

<p>It will look something like this:</p>

<pre><code>userMessages: {
    uid1: {
        gid1: {
            mid1: true
        }
        gid3: {
            mid6: true,
            mid12: true
        }
        ...
    }
    uid2: {
        gid1: {
            mid2: true
        }
        gid5: {
            mid13: true,
            mid25: true
        }
        ...
    }
    ...
}
</code></pre>

<p>So now I could quickly fetch the locations of all the messages for a specific user, and update the username with a single updateChildren() call.</p>

<p>Is this really the best approach? Do I really have to duplicate so much data (millions of messages) only because I'm referencing a dynamic value (the username)?</p>

<p>Or is there a better approach when dealing with dynamic data?</p>