Choose a data structure for Firestore

If we ask to Write data structure for Firestore and chatrooms. Most solutions would look like this.

Firestore is a NoSQL document database provided by Google Cloud Platform. It allows you to store and sync data in real-time for web, mobile, and server applications. Here's an example of a data structure for Firestore that could be used for chatrooms:

1. Collection: Chatrooms
- Document: {chatroom_id}
- Field: name (string) - The name of the chatroom.
- Field: participants (array) - An array of user IDs who are participating in the chatroom.
- Field: created_at (timestamp) - The timestamp when the chatroom was created.

2. Collection: Messages
- Document: {message_id}
- Field: chatroom_id (string) - The ID of the chatroom where the message belongs.
- Field: user_id (string) - The ID of the user who sent the message.
- Field: content (string) - The content of the message.
- Field: timestamp (timestamp) - The timestamp when the message was sent.

With this data structure, you can create a chatroom by adding a new document to the "Chatrooms" collection. Each chatroom document contains information such as the name, participants, and creation timestamp. Whenever a message is sent in a chatroom, you can add a new document to the "Messages" collection. Each message document contains information like the chatroom ID, user ID of the sender, message content, and the timestamp.

This structure allows you to query and retrieve chatrooms based on different criteria, such as listing all chatrooms a user is participating in or fetching all messages in a specific chatroom. You can also order the messages by their timestamps to display them in the correct order in the chat interface.

Remember that this is a basic example, and depending on the requirements of your chat application, you may need to modify or expand this structure to suit your specific needs.

BUT
Getting data that is naturally hierarchical might become increasingly complex as your database grows.


Root-level collections

What's a possible use case? In the same chat app, for example, you might create one collection for users and another for rooms and messages. 
 
Apologies for the confusion. If messages are stored as a subcollection within each chatroom document, here's an updated data structure for Firestore with chatrooms and messages:

1. Collection: Chatrooms
   - Document: {chatroom_id}
     - Field: name (string) - The name of the chatroom.
     - Field: participants (array) - An array of user IDs who are participating in the chatroom.
     - Field: created_at (timestamp) - The timestamp when the chatroom was created.

     - Subcollection: Messages
       - Document: {message_id}
         - Field: user_id (string) - The ID of the user who sent the message.
         - Field: content (string) - The content of the message.
         - Field: timestamp (timestamp) - The timestamp when the message was sent.

With this updated structure, chatrooms are still stored as documents in the "Chatrooms" collection, and each chatroom document can have a subcollection called "Messages". Within each chatroom's "Messages" subcollection, message documents are stored. Each message document contains fields such as the user ID of the sender, the message content, and the timestamp.

To add a new chatroom, you create a document in the "Chatrooms" collection and then add message documents within its "Messages" subcollection when messages are sent within that chatroom.

This structure allows you to query and retrieve chatrooms along with their associated messages. You can fetch all chatrooms a user is participating in and retrieve the messages within each chatroom, either all at once or paginated based on the needs of your application.

Please note that Firestore has a maximum depth limit of one level of subcollections, so if you need additional levels of nesting, you may have to consider alternative approaches or use a different database structure.
 
Here's an example where we use marks or brands for cars, and each car is stored as a document in a collection:

1. Collection: CarMarks (to store car marks/brands)
   - Document: {mark_id}
     - Field: name (string) - The name of the car mark/brand.

2. Collection: Cars
   - Document: {car_id}
     - Field: mark_id (string) - The ID of the car mark/brand that the car belongs to.
     - Field: model (string) - The model of the car.
     - Field: year (integer) - The manufacturing year of the car.
     - Field: color (string) - The color of the car.
     - Field: price (float) - The price of the car.

In this example, we have two collections: "CarMarks" and "Cars". The "CarMarks" collection stores car marks or brands, and each mark/brand is represented as a document. The document contains a field called "name" which holds the name of the car mark/brand.

The "Cars" collection stores information about individual cars. Each car is represented as a document, and the document contains fields such as "mark_id" to associate the car with a specific mark/brand (using the ID of the mark/brand from the "CarMarks" collection), "model" to specify the car model, "year" to indicate the manufacturing year, "color" to store the color of the car, and "price" to store the price of the car.

To add a new car, you create a document in the "Cars" collection and provide the relevant fields such as the mark/brand ID, model, year, color, and price.

This structure allows you to perform queries and retrieve information about cars based on different criteria. For example, you can fetch all cars belonging to a specific car mark/brand by querying the "Cars" collection with the desired mark/brand ID. You can also query and filter cars based on their model, year, color, or price.

 To create or overwrite a single document, use the following language-specific set() methods:

 db.collection('vehicles').document('vehicle').set(data)

When adding data to Firestore using the `set()` method, the following behavior occurs:

1. If the document does not exist, a new document will be created with the provided data.

2. If the document already exists, its existing contents will be completely overwritten with the newly provided data.

However, if you want to merge the provided data with the existing document instead of overwriting it entirely, you can specify the merge option. This allows you to update specific fields within the document without affecting the rest of the data. Here's how you can do it:


By setting `{ merge: true }`  the existing document will be updated with the provided data, and only the specified fields will be changed. Any fields that are not specified in the new data will remain unchanged in the existing document.

This allows you to selectively update specific fields within a document while keeping the rest of the data intact, providing more flexibility when working with existing documents in Firestore.

car_ref = db.collection('vehicles').document('bmw_chassis_number')

city_ref
.set({
   
'fuel': 'Benzine'
}, merge=True)

Example


Let's consider a scenario where we need to update the categories of cars in our mobile app. Our approach involves overwriting the current categories in the mobile app with the categories and their calculated counts obtained from our Django app.

In this scenario, we have a Django app that performs calculations and determines the categories of cars along with their corresponding counts. Our goal is to ensure that the mobile app reflects the most up-to-date information by replacing the existing categories with the latest data from the Django app.

To achieve this, we retrieve the updated categories and their counts from the Django app. Then, in the mobile app, we overwrite the current categories with the retrieved data, ensuring that the app always displays the most recent categories and their respective counts.

By following this approach of overwriting the existing categories with the updated data from the Django app, we maintain consistency between the two platforms and ensure that the mobile app accurately reflects the categories of cars and their calculated counts. 

 class Command(BaseCommand):
    def handle(self, *args, **options):
        cred = credentials.Certificate("path_to_file")
        firebase_admin.initialize_app(cred)
        db = firestore.client()
        collection = db.collection("filter")
        merks = VehicleMerk.objects.all()
        for merk in merks:
            self.update_merk(merk, collection)

    def update_merk(self, merk, collection):
        # up-to-date information by replacing the existing categories
        res = collection.document(merk.name).set(merk.to_json())
        print(res)

Links

https://firebase.google.com/docs/firestore/manage-data/structure-data

https://firebase.google.com/docs/firestore/manage-data/add-data



Comments