How do I structure data common to all users in Cloud Firestore?

488964492:
JBrown

I'm working on an app similar to Goodreads and using Cloud Firestore for the backend. My current DB structure is something like this:

Users (collection)
    uniqueUser1 (document)
        user1Metadata (fields)
        ...
        books (sub-collection)
            book1 (document)
                globalBook1Metadata (fields such as genre, year published, etc)
                ...
                user1Book1Metadata (fields such as rating, comments, date added, etc)
            book2 (document)
                globalBook2Metadata (fields such as genre, year published, etc)
                ...
                user1Book2Metadata (fields such as rating, comments, date added, etc)
    uniqueUser2 (document)
        ...
        books (sub-collection)
            book2 (document)
                globalBook2Metadata (fields such as genre, year published, etc)
                ...
                user2Book2Metadata (fields such as rating, comments, date added, etc)
            book3 (document)
                ...

I have a users collection which contains user documents. Each user document contains some unique user metadata along with a sub-collection of books. Each book in the sub-collection has some global metadata and data that is unique to the user.

This seems horribly inefficient in terms of storage. I am storing the global book metadata every time a user adds a book. In the above example, book2 is stored twice. So my next thought was to add a books collection at the root level like this:

Books (collection)
    book1 (document)
        globalBook1Metadata (fields such as genre, year published, etc)
    book2 (document)
        globalBook2Metadata (fields such as genre, year published, etc)
    book3 (document)

This is much better in terms of storage. I can now just store the book id in the user document and query this collection to get the global book metadata.

But now there is a new problem. Say I want to filter a user's library based on the genre. Well, because genre is only stored in the Books collection, I have to get all the books from the Books collection that match the ids in the user's book sub-collection. That has the potential to be a very large number of reads which is expensive.

So my question comes down to 2 parts:

  1. Is there a way to send a single query that gets all the books from Books that have matching ids to the user's book sub-collection? If so, that would be a great solution.

  2. If not, what is the best way to structure this data so that I am not doing an excessive amount of R/W or using way too much storage?

I am a frontend dev so this is new territory for me. Thanks in advance!

Milen Minchev

You are on a good way with the second approach, the first one it will still work but is not scalable.

If you want to keep the current structure you have:

-Collection of books

-- document_id1

-- document_id2

You can achieve decent result with having array of UID's of books in every user (you can add and remove them with ArrayUnion and ArrayRemove) then you can query based on the user selected genre from the filter and the array of saved UID books with the "in" operator it will look something like:

const q = query(collection(db, "books"), where('genre', '==', 'comedy'), where('bookIdField', 'in', user.uidArrayFavBooks));

In this way you will get only needed results with one query.

If you want to optimize it slightly you can separate the general UID array in user document to a different genres arrays if you know for 100% all genres input, something like:

comedy: ['id1', 'id2']
action: ['id1', 'id3', 'id6']
...and so on

Note: If genres options are not controlled by you I will not advice you to do it, because is not good practice to rely on predictions of user data input.

As a workaround you can store object with the UID and genre in array and pass it to the query with filter method for selected genre, as example:

const userFavBooks = [
    { id: 1, genre: "drama" },
    { id: 2, genre: "action" },
    { id: 3, genre: "comedy" },
    { id: 4, genre: "drama" },
  ];
const filteredBooksArray = userFavBooks.filter((e) => e.genre === "drama").map((e) => e.id) // [1,4]

const q = query(collection(db, "books"), where('bookIdField', 'in', filteredBooksArray));

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How do I delete ALL collections for a project in Google Cloud Firestore?

How do I filter data from cloud firestore twice?

How do I represent hierarchical data in Cloud Firestore using a struct?

Ionic App using Cloud Firestore - See data for all users

All users share the same data created, how do i fix it?

Cloud firestore rules - how do I view a users rights by accessing different collections in the store?

Dating app - Which database structure do I need in Firebase Firestore to query all users except those who disliked me?

May I know how to retrieve all the data of users from firebase firestore of a mobile application in Android Studio?

How do I initialize Cloud Firestore in php?

How do I paginate with Cloud Firestore?

How to store Google Cloud Firestore data locally having a complex structure?

How do i check if a field-value exists across all documents in a collection in Cloud Firestore?

How do I send data from Pub/Sub to Google Cloud Firestore?

How do I access the data from Cloud Firestore database in Firebase using Swift in Xcode?

Firebase Cloud Messaging: how to send data message to all users?

How do I redirect after auth users register to collection in Firestore?

Cloud Firestore Data Structure making effectively

How do I list all cron jobs for all users?

How do I filter the data sent by firestore

how do I fetch data from the Firestore?

how do I display firestore data with React

How do I further optimize this Data Structure?

How do I get data on a hierarchical structure?

How do I deserialize this type of data structure

How do I create a data structure?

How do I organize data by common traits?

How do I enumerate all paths in a Directed Acyclic Graph structure using Python, when the data structure can only be discovered via traversal?

How to structure data for orders in firestore?

How to do Sorting and Indexing of data in between on Cloud Firestore?