2

I'd like some clarification about Cloud Firestore's read pricing with relation to Reference types. In my current scenario, I have a chat room that displays a list of messages in a conversation. A message looks like this...

{
  "id": "...",
  "text": "Hello World",
  "createdBy": Reference(/users/userID)
}

When rendering the message I have access to the text, but I also need access to the createdBy user. Currently, I'm passing the createdBy reference to another component (in React) and then fetching that document there to display the user's avatar and username.

This is working well enough but I'm concerned that this results in a read to the database for every message in the conversation, which could add up very quickly. I'm almost certain that this will result in additional reads per message, but is Firebase intelligent enough to cache the users?

In other words, if I have 5 messages created by /users/userA will each message count as a read to the database, or would it just be one read for each user in the conversation?

If Firebase isn't able to cache this, it would seem I need to denormalize the data and duplicate the username and avatar on the message document rather than just relying on the reference itself. This seems to kind of limit the benefit of References, though.

Jesse Dunlap
  • 1,280
  • 1
  • 16
  • 22
  • Here is the correct answer- https://stackoverflow.com/questions/48787918/firestore-reading-data-with-references-do-increase-in-number-of-requests – Yash Jan 02 '21 at 06:42
  • Thanks for sharing. Generally the conclusion I came to is that denormalizing the essential data is probably the way to go. For my chat application, I stored the sending user’s name and avatar URL with each message, as well as a reference to the actual user. This did result in old messages not updating if the user changed this information but that was a conscious decision on my part, and could be solved for by retroactively updating the old messages if you wanted. (This is why denormalization tends to be write heavy instead of read heavy.) – Jesse Dunlap Jan 02 '21 at 16:42
  • It also might be valuable to some to know that without doing this, making a reference read for every message did actually add up quite quickly and we ended up exhausting the free Firebase plan just in development. So while it may be a premature optimization, at least in our case it wasn’t too premature. – Jesse Dunlap Jan 02 '21 at 16:44

1 Answers1

0

Cached documents will be reused and not incur reads when accessed. It doesn't matter if you create the DocumentReference yourself, or get it from the field of another document. Reading a document with a DocumentReference doesn't cause an extra read. The client has to be explicit about reading it.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Thanks for verifying that, that certainly makes things a little easier. Does it follow then that it's generally safe to use references how I've described rather than de-normalizing the data? (De-normalizing might still make sense in some cases, of course.) – Jesse Dunlap Apr 02 '19 at 22:52
  • A reference is just a strongly typed string that points to a document. There is nothing inherently unsafe or costly about them. – Doug Stevenson Apr 02 '19 at 23:16
  • Sorry, let me clarify. I mean the practice of storing a Reference to a document on another document, and then making essentially two reads (e.g. reading the message, and reading its author) rather than just storing some basic data like username and picture on the message itself (one read). – Jesse Dunlap Apr 02 '19 at 23:49
  • You have to determine what's best for your use case. The option to use a reference is there if you want it. Or, if you want, you can duplicate data into multiple documents. There is no "right way" - just the way you have figured is best for you. – Doug Stevenson Apr 02 '19 at 23:57
  • @JesseDunlap You may watch this official Firebase video starting at 4:37: https://www.youtube.com/watch?v=Elg2zDVIcLo&t=277 – Renaud Tarnec Apr 03 '19 at 06:29