Closer look at Firebase set versus update

In RESTful terms “set” is like an PUT, and an “update” is like a PATCH, but there is a bit more interesting distinctions under the covers.

Jason Byrne
Mar 30, 2017 · 5 min read
Firebase… pirate…. PATCH… get it?

I thought I knew how these two methods work and the distinction between the two. But after my co-worker, Karl, and I dug into it further… turns out there was a lot we did not know.

Let’s start with the basics.

Calling set on a given object will replace it completely. So if we have an object like this:

So then if we do this…

Our object now looks like this…

So as you see with set it will completely replace whatever you have at that reference. Now let’s go back to our original object and then see how update would impact it differently.

That would make our original object:

As you see it works like a PATCH instead of a PUT. It updates the fields that we push in and leaves the other ones alone. The nice thing is we can also add new fields with an update:

Which gives us:

Nice! So it is more like an UPSERT than an UPDATE. So in reality you can almost always use “update” instead of “set” unless you really want to blow away what was previously there. You can use the update with any node that doesn’t exist yet and it will create it, just like set would.

Let’s dig a little deeper.

So we understand now what it does from the side of writing the update, but how do the two look different from the side of the user listening for the new value? They look a lot different, it turns out.

If you are just looking at your console log and spitting out the snapshot that you receive from the client SDK, you will not notice any difference.

The above code will look exactly the same if you a set or an update… that is the console will reflect the entire object with all of its values. Until today I wrongly assumed that meant that behind the scenes Firebase was sending the entire endpoint (and all its children) each time anything changed under that endpoint — whether set or update. I was wrong.

Let’s go back to our original object:

And now do a set where we don’t change anything…

Now take a look at the actual traffic through the socket…

I set an ref.onValue() and that is what you see on the first line. And then two second later, I did the set where no values changed. It was nice to see that the Firebase client was smart enough to not send any data to the socket since no values changed.

So now let’s change one of the values…

And here is what came through the web socket…

Notice that this time after I executed the set, the on value listener fired again. But also notice that it sent the entire object! So whereas before when no values changed, it was smart enough to diff it and not send me anything… now it is NOT smart enough to diff it and only send me the changed values!

Interesting… now let’s see how that differs when we do the same tests with update. I‘m going to go back to our original “Jason Byrne” values and run this update three different ways.

That gives us this over the socket…

This looks the same as the set. We sent the data to Firebase with “update” but the data was identical. Firebase was did not hit our on value at all. Good!

Now let’s change data, but with an update we don’t need to send any data except the part that has changed. So we can leave off the last name.

Watching the socket frames in the network tab of the Chrome developer console, we see something great…

On the second callback the on(value) listener, we see that it only sent us the diff of what changed. It did not have to use up the extra bandwidth by sending the last name again, since it stayed the same.

However, conveniently, when we view the snapshot.val() in our code, we get the entire object. This is great because we don’t have to merge the diff into our previous value ourselves.

Okay now, so I wondered what would happen if I use “update” and send the entire object (first name and last name), even though only first name changed.

Which results in…

Sweet! Unlike when we did the same thing with the set method, the diff works appropriately with the update. So even if we send unchanged data to Firebase, as long as we are using an update the end user will only have to receive the diff!

Sometimes it is a pain to diff it on the application side and really easy just to send Firebase the entire object — change or not. So we might very well find ourselves thinking that we might as well use “set” since we’re sending the entire object anyway.

It would be nice if Firebase applied that same logic to a “set” and only sent the diff. Maybe there is some good reason they can’t do so. Either way, now we know how important it is to use “update” and avoid “set” unless we really have the need to junk the existing object and replace it.

The end user performance will benefit from it!

Jason Byrne

Written by

Entrepreneur, developer, historian, journalist, Christian, family man, and track & field fan. VP of Software Development @ FloSports. Founder of MileSplit.