1

Summary

How could I model my database in Firebase to keep, for example, reviews in a specific page updated with the users info, this is, if a user changes it's avatar or name, the reviews should also display the updated data of the user. I've used MongoDB most of the time, with Mongoose, and I am now working on a mobile app with Firebase. In Mongo I would just store a ref to the user in the review, and populate the field to retrieve the data I wanted from the document. Is there something like this in Firebase, and is it even a good or acceptable practice?

Quick Questions

  1. Is there something like ".populate()" in Firebase?
  2. Should I model the documents as much as possible to have the data that will be used in the view, and avoid "joins"?

Example

We have a users collection, and a store collection with reviews in it.

As far as I've read, you should minimize the doc reads, and so we should model our data with the specific values we need for the view were they will be used, so that we only need to do one query.

For the sake of simplification, let's say:

User has a name, email, avatar

users: {
    user_id_1: {
        email: "user1@gmail.com",
        name: "John Doe",
        avatar: "some_firestore_url"
    }
}

Should the store collection:

  1. Have nested collection of reviews like this
stores: {
    store_id_1: {
        name: "Dat Cool Store!",
        reviews: {
            user_id_1: {
                name: "John Doe",
                avatar: "some_firestore_url",
                text: "Great store love it!",
                timestamp: "May 07, 2020 at 03:30"
            }
        }
    }
}

The problem I see with this, is that unless we use a function that updates every field in every document with the new values there is no other way to update the data in name and avatar.

  1. Have the user_id in a field and query for the user information after:
stores: {
    store_id_1: {
        name: "Dat Cool Store!",
        reviews: {
            review_id_1: {
                user: "user_id_1",
                text: "Great store love it!",
                timestamp: "May 07, 2020 at 03:30"
            }
        }
    }
}

This is the mimicking the way I would do in MongoDB.

Sorry if some of it sounds confusing or I didn't explain myself the best way, but it's 4 o'clock in the morning here and I'm just trying to get it right :)

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
ImInYourCode
  • 567
  • 1
  • 7
  • 19
  • I had switched to Firestore for a while but saw that changes do not apply immediately. The users needs to re-start that activity if you are not using any realtime listerners or so. I use realtime database to show username and stuff which needs to be shown everytime. It reflects the changes within half a second. – Dharmaraj May 07 '20 at 05:00

2 Answers2

1

How could I model my database in Firebase to keep, for example, reviews in a specific page updated with the user's info, this is, if a user changes its avatar or name, the reviews should also display the updated data of the user.

Without knowing the queries you intend to perform, it's hard to provide a viable schema. We are usually structuring a Firestore database according to the queries that we want to perform.

In Mongo I would just store a ref to the user in the review, and populate the field to retrieve the data I wanted from the document. Is there something like this in Firebase, and is it even a good or acceptable practice?

Yes, there is. According to the official documentation regarding Firestore supported data-types, a DocumentReference is one of them, meaning that you can store only a path to a document and not the entire document. In the NoSQL world, it's quite common to duplicate data, so to have the same data in more than one place. Again, without knowing the use-case of your app it's hard to say whether using normalization it's better than holding only a reference. For a better understanding, I recommend you read my answer from the following post:

And to answer your questions:

  1. Is there something like ".populate()" in Firebase?

If you only store a DocumentReference, it doesn't mean that the data of the document that the reference is pointing to will be auto-populated. No, you first need to get the reference from the document, and right after that, based on that reference, you have to perform another database call, to actually get the data from the referenced document.

  1. Should I model the documents as much as possible to have the data that will be used in the view, and avoid "joins"?

Yes, you should only store the data that you actually need to be displayed in your views. Regarding a JOIN clause, there isn't something like this supported in Firestore. A query can only get documents in a single collection at a time. If you want to get, for example, data from two collections, you'll have at least two queries to perform.

Another solution would be to add a third collection with data already merged from both collections so you can perform a single query. This is already explained in the link above.

Some other information that might be useful is explained in my answer from the following post:

Where you can find the best practice to save data into a document, collection, or subcollection.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
0

For me, the way I would go ahead with structuring my json collection also depends on the size of data, I am trying to store in the collection.

Let's say the number of users if small and I only want to support a thousand users. So in that case, I can go with this structure.

{
  "store_id_1": {
    "name": "Dat Cool Store!",
    "reviews": [
      {
        "user_id_1": {
          "name": "John Doe",
          "avatar": "some_firestore_url"
        },
        "text": "Great store love it!",
        "timestamp": "May 07, 2020 at 03:30"
      },
      {
        "user_id_2": {
          "name": "John Doe 2",
          "avatar": "some_firestore_url 2"
        },
        "text": "Great store love it! TWO",
        "timestamp": "May 27, 2020 at 03:30"
      }
    ]
  }
}

So now, you can have all the user info embedded in the stores collection. This will reduce your reads too.

But in case you want to scale it, then, I would suggest only store the users metadata and then make another read from users collection.

Hope this helps!

zenwraight
  • 2,002
  • 1
  • 10
  • 14