Firebase Fundamentals Retrieving & Writing Data
Transcript from the "Retrieving & Writing Data" Lesson
>> So now that we can kinda see how to construct data, let's look at retrieving data. It all starts with a reference, which we saw in the quick example. We can create a collection reference. So we pass in collection, and then we pass in our FireStore example or a FireStore instance, and then we have now a reference out for users.
[00:00:24] And then what we tend to do is the sort of the naming convention that I use is the name of the reference, and then Col if it's a collection. Or if I wanna get a single document, I can write a full path out to it. So users/david would get me to the document, a single document of David.
[00:00:44] And then I'll just say userDoc or davidDoc, usually you don't know the ID name. And now from there, I have the beginnings of being able to access data at that location. And then if I want to get this data and in real time, I call that method with onSnapshot, and then it returns back to me the data snapshot.
[00:01:06] And snapshot is a very fitting name for this because we're not getting the data as is in that spot. We're getting the data as it was when that transaction fired because this is a real time system, so things can change all the time. So at that point, that is what the data look like.
[00:01:23] Another update happened, well, that's gonna call back again, and that's what the data looks like at that point. And also, like I mentioned, the snapshot is gonna have tons of other information that we can use to build really powerful apps. So within documents, it's simple, if you're listening to onSnapshot with a document, it's going to come back with just data.
[00:02:01] What I find is most common is that people do map over and just return the data back. Again, this is my will sentence execution context moment. Right here, we do not await writes that happen or any updates that happen in Firebase. When I update the name of this userDoc, I'm not waiting for it to get back.
[00:02:26] Well, I do care, but I do not care to track that it succeeded or it errored in this case. What I care to do is get when this update fires. So the first time onSnapshot runs, it's just gonna have my name. But then when I update it with an exclamation mark, it's gonna fire again.
[00:02:43] What's important note here is that even if this transaction fails, cuz a lot of people, they wanna wait to see, hey, if it fails, I wanna be able to try it again. You don't have to do that. If this fails for network reasons, it will sit in a background queue and waits to keep trying until it's able to do it again.
[00:03:04] So you don't actually have to worry about managing the state of or the network success of any of your writes to Firestore. Firestore handles all of that behind the scenes for you.
>> Are the docs out of date? On the Add Data docs, they use await setDoc in multiple places.
>> So they show you in the docs that you can do it because there are times where you do want to await the results. But that is only when you are saying, it is paramount in some situation that I understand that I received this update from the server.
[00:03:48] Because that's what await does is it says, hey, I want to know that the server acknowledged that this happened. There are situations where that is important, but for the most part, if you're using onSnapshot, it is not. If you are not using onSnapshot, though, if you are just doing a traditional, which is possible we actually have a subset of Firestore library called Firestore Lite.
[00:04:15] Which is a much smaller version that doesn't have the offline capabilities in real time streaming, that you do follow more of a request response, because it is basically a REST wrapper. But in this world of real time updates, while you can await and there might be cases too and we document that that happens, we recommend that you don't await.
[00:04:36] And if you do care about listening to errors, you do that in the second callback. That's a good question. Our documentation documents everything that we expose within the library. So writing data, we can do that mutation functions. Calling setDoc, this does something destructively. So whatever data existed there before gets overwritten.
[00:05:01] So this could have had name was Mark, but then if I call with David, it's just going to erase that entirely. And this is good for when you're doing create style operations. And then we have updateDoc, which is a lot easier on the doc, where it doesn't do a destructive update.
[00:05:21] It just looks at the delta of the difference and it updates that document. But the catch with updateDoc is that the document must exist for it to be updated or you're gonna get an error. So to get the best of both worlds here is there's actually a second option within setDoc called merge, and it operates like an update, but for a document that may not exist.
[00:05:48] So in this case, I have a path of users/new_user_maybe. And I can write the name, and maybe this user exists, maybe they don't. But what I wanna do is I'm gonna merge it, so if they do exist, it's just gonna update the name. So it's gonna act like an update, but it won't error if the document doesn't exist.
[00:06:08] I find that the vast majority of times, this is what I'm using when I'm building my apps is merge true kinda just tends to get you there. There are certain cases, though, where each one you want that specific behavior, but this is sort of the nice middle ground behavior, yes.
>> If you have the path incorrect and it keeps trying to get real time updates in the queue, is there any way to stop listening to the updates? Or could this cause a slowdown if the connection is open for too long?
>> That's a great question. If there's nothing there, you're not gonna get anything back.
[00:06:45] And you're only going to get updates when something happens to that document. So in general, you should limit the amount of things that you are subscribing to cuz that's just opening yourself up to receiving updates. But if there's nothing there and it doesn't exist, you're not going to be getting updates.
[00:07:03] So if it's null forever, you're just never gonna get updates back from that. It's a good question. And then deleting documents also, create a document out to what you want to delete, pass it in, and then it gets deleted. So one thing too that's very important to understand is that when you're working with a real time system, how you name your paths are very important.
[00:07:28] And not just for the collection name, but specifically for document names. So collection of users make sense, that's what I would name a table of users. But this path right here of some-name, this operates a lot like my primary key. So how do I make sure that in a real time system that I'm not overriding all these updates on certain documents?
[00:07:53] Well, one of the things that we provide is the way to generate IDs. And so we do that on a client base. And so in this case, rather than writing out to and having to think up of a name for every type of document. Or for even me having to think about what the primary key, so to speak, of this collection or for this document would be.
[00:08:13] What I'd rather do is instead of that, I can pass in users column to this method called addDoc. And what that will do is it will add this new user, but it will automatically generate a key for them. And generated keys in real time systems are great because if you are constantly trying to write to the same document, you get lots of race conditions.
[00:08:33] Because one person tried to write something here. Wait, another real time update came in, write it there. There are ways to do this, which we're gonna see at the very end of this section atomically with transactions. But for the most part, if you distribute all of your documents to have generated IDs, you don't see as many flickering updates and race conditions.
[00:08:56] And then, yes, a lot of times too when people get started with Firebase, they think that generated ID happens on the server, but it actually happens within the client. So just by creating a blank document with a parent of a user collection, I call .id on it, and it has a generated ID.
[00:09:15] And then from there, I could set it. But I get access to that ID, I find that that ID is really great for syncing it with DOM element IDs. So that way you can find it and update its data quite easily.