Firebase database structure - need advice

2019-07-18 07:59发布

问题:

I know this question might be seen as an opinion-based one, however I think it's worth to discuss the way to properly structure database. I work on iOS app in Swift and decided to use firebase as my backend service

Let's start with the app description

The app aims to provide tracking and social features to book reading experience, as well as create books database. User adds book, fill basic info like title, author, language, number of pages etc. Next, this book is visible on the list in app, where user can easily access the book info and save the information on which page he/she recently ended reading. After a book is marked as read, user obtains experience points and badge. Ultimately, the user is going to be able browse friend's achievements, create a leaderboard etc.

This is my idea of database structure:

  Users:
    user_id:121jhg12h12
      email: "john@doe.com"
      name: "John Doe"
      profile_pic_path: "https://...".
      language: "en"
      exp_points: 1284
      friends: [user_id]
      books: [[book_id, status, current_page, start_date, finish_date]]
      badges: [[badge_id, get_date]]

  Books:
    book_id: 3213jhg21
      title: "For whom the bell tolls"
      author: "Ernest Hemingway"
      language: "en"
      pages_count: 690
      ISBN: "21hjg1"
      year: 2007

  Badges:
    badge_id:213hg12
      name: "Great reader!"
      image_path: "https://...".

I used pseudo code filled with some dummy data instead of JSON format to make it more readable, if I failed, let me know.

What I would like to achieve by asking this question is to obtain an explicit answer if my approach is right, or should I change something in database structure to hone future scalability and general performance.

Note that I'm aware of the fact that this question may be considered as more suitable for code review forum, but as you know, rarely anybody answers there, especially in such narrow topic like firebase database structure.

thanks in advance

回答1:

In my opinion, your book and badges data models look totally fine. They will be public to any user in the app and do not store any complex data.

Now to get to the user objects: 1) For this type of app, where user interactions will be occurring, you will most likely want to protect the privacy of your users by not storing their email (since the user object has to be readable by others). The email will already be embedded in the user's authentication token, so saving it into the database as well is redundant and reduces privacy. If you really wanted to save it, you could make a new object named "user_private" and have it only be readable by the user himself.

2) For an app where a friends list is present, you will also need a system of friend requests. To do this, I would suggest creating a key named "outgoing_requests", that is all the friend requests you have sent to other users (w/ userID) that are still incomplete. Also, create a key named "incoming_requests", that contains requests other users have sent you. This is what you would use to create a friend requests page and allow a user to accept or deny. This creates some complexities with the JSON rules. I would lay it out like this:

  • outgoing_requests: writable by user himself (cancel request) or by the user who has the id of request( accept or deny request)
  • incoming_requests: writable by user himself (accept or deny) or by user who has id of request (cancel)
  • friends_list: writable if new entry and id is part of incoming requests, or deleting and this is my user

3) You will also likely be querying your user's books based on timestamps. Therefore, I would lay it out so this is easy to accomplish (an array won't work because the user may start reading a book they havent opened in a while and the ordering will be mixed up). You could store user's books like this:

books:
  book_id:
    lastopened_date:
    status:
    current_page:
    start_date:
    finish_date:

Then, in status, either store "complete" or "incomplete". "lastopened_date" & "current_page" will be used if incomplete. "start_date" & "finish_date" will be used if complete.Then it is easy to query for finished books by what date they were finished, and query for unfinished books by what date they were last opened. Badges can be stored like this:

badges:
  badge_id:
    get_date:

Storing the books & badges like this makes it much easier to query based on timestamps. This is everything I can think of for now. Let me know if you have any questions.