How to organize user's data in FireStore - database

I would like to create a database on Firestore that would look like this :
Collection A (Users)
Document A (User 1)
Data 1
Data 2
ThisListOfData
ThisThing1
ThisSubData1
ThisSubData2
ThisThing2
...
Document B (User 2)
Each user have his data (username, ...). But one of his data (ThisListOfData) is a list of things (a list of activities, like yoga, sport, ...). And for each activities (ThisThing1, ...) there is subData. I want to do this like that, because the user can subscribe to more activities, delete some...
It's my first time using Firestore so I have no idea how to do that. The "ThisListOfData" should/can be a collection ? Or a data like a list of string ? If someone could help me on this one, and how to get all the "Things" inside "ThisListOfData" to check the activities the user subscribed to ?
Thanks alot

When using Firestore or the Realtime Database it is more importand how you "get" the data when you try to figure out "where" and how to "structure" it.
When deciding on this always think of "where will I use this data?" and "how will I query it?".
The structure you shown us is quite OK. What I would recommend is that if there are some data parts that will be accessible also for other users to store those to a separate collection as Users and take a lot of effort to make the collection Users as secure as possible. For that reason to reduce complexity in security rules I always prefer and recommend to store such data (that should be awailable for others) into separate collections.
Also if you want to save something as data field of a document like map or array or if you want to save it as subcollection depends mostly on how you want to get the dat later or if you need to query on it. If you plan to run queries on it and sort such data I would recommend to save it as collection.
Saving data in arrays has some donwsides like updating that works only for the whole array.

Related

Firestore: Running Complex Update Queries With Multiple Retrievals (ReactJS)

I have a grid of data whose endpoints are displayed from data stored in my firestore database. So for instance an outline could be as follows:
| Spent total: $150 |
| Item 1: $80 |
| Item 2: $70 |
So the value for all of these costs (70,80 and 150) is stored in my firestore database with the sub items being a separate collection from my total spent. Now, I wannt to be able to update the price of item 2 to say $90 which will then update Item 2's value in firestore, but I want this to then run a check against the table so that the "spent total" is also updated to say "$170". What would be the best way to accomplish something like this?
Especially if I were to add multiple rows and columns that all are dependent on one another, what is the best way to update one part of my grid so that afterwords all of the data endpoints on the grid are updated correctly? Should I be using cloud functions somehow?
Additionally, I am creating a ReactJS app and previously in the app I just had my grid endpoints stored in my Redux store state so that I could run complex methods that checked each row and column and did some math to update each endpoint correctly, but what is the best way to do this now that I have migrated my data to firestore?
Edit:here are some pictures of how I am trying to set up my firestore layout currently:
You might want to back up a little and get a better understanding of the type of database that Firestore is. It's NoSQL, so things like rows and columns and tables don't exist.
Try this video: https://youtu.be/v_hR4K4auoQ
and this one: https://youtu.be/haMOUb3KVSo
But yes, you could use a cloud function to update a value for you, or you could make the new Spent total calculation within your app logic and when you write the new value for Item 2, also write the new value for Spent total.
But mostly, you need to understand how firestore stores your data and how it charges you to retrieve it. You are mostly charged for each read/write request, with much less concern for the actual amount of data you have stored overall. So it will probably be better to NOT keep these values in separate collections if you are always going to be utilizing them at the same time.
For example:
Collection(transactions) => Document(transaction133453) {item1: $80, item2: $70, spentTotal: $150}
and then if you needed to update that transaction, you would just update the values for that document all at once and it would only count as 1 write operation. You could store the transactions collection as a subcollection of a customer document, or simply as its own collection. But the bottom line is most of the best practices you would rely on for a SQL database with tables, columns, and rows are 100% irrelevant for a Firestore (NoSQL) database, so you must have a full understanding of what that means before you start to plan the structure of your database.
I hope this helps!! Happy YouTubing...
Edit in response to comment:
The way I like to think about it is how am I going to use the data as opposed to what is the most logical way to organize the data. I'm not sure I understand the context of your example data, but if I were maybe tracking budgets for projects or something, I might use something like the screenshots I pasted below.
Since I am likely going to have a pretty limited number of team members for each budget, that can be stored in an array within the document, along with ALL of the fields specific to that budget - basically anything that I might like to show in a screen that displays budget details, for instance. Because when you make a query to populate the data for that screen, if everything you need is all in one document, then you only have to make one request! But if you kept your "headers" in one doc and then your "data" in another doc, now you have to make 2 requests just to populate 1 screen.
Then maybe on that screen, I have a link to "View Related Transactions", if the user clicks on that, you would then call a query to your collection of transactions. Something like transactions is best stored in a collection, because you probably don't know if you are going to have 5 transactions or 500. If you wanted to show how many total transactions you had on your budget details page, you might consider adding a field in your budget doc for "totalTransactions: (number)". Then each time a user added a transaction, you would write the transaction details to the appropriate transactions collection, and also increase the totalTransactions field by 1 - this would be 2 writes to your db. Firestore is built around the concept that users are likely reading data way more frequently than writing data. So make two writes when you update your transactions, but only have to read one doc every time you look at your budget and want to know how many transactions have taken place.
Same for something like chats. But you would only make chats a subcollection of the budget document if you wanted to only ever show chats for one budget at a time. If you wanted all your chats to be taking place in one screen to talk about all budgets, you would likely want to make your chats collection at the root level.
As for getting your data from the document, it's basically a JSON object so (may vary slightly depending on what kind of app you are working in),
a nested array is referred to by:
documentName.arrayName[index]
budget12345.teamMembers[1]
a nested object:
documentName.objectName.fieldName
budget12345.projectManager.firstName
And then a subcollection is
collection(budgets).document(budget12345).subcollection(transactions)
FirebaseExample budget doc
FirebaseExample remainder of budget doc
FirebaseExample team chats collection
FirebaseExample transactions collection

How to store results of an advanced search?

Currently I am trying to add a new functionality to my system in which users will be able to see customs lists of products.
For the creation of these lists I will mostly likely use an algorithm or some criteria that will be used to gather data from my database, or sometimes use hand-picked items.
I wonder what is the best way to do that, in terms of storage and computational time. I was thinking about using an object for my model (something like CustomList), that will store some attributes regarding to this list (that is basically filled with products which are results of an advanced search in my database) and by doing so, store a query string or something like that so it can be reprocessed periodically and if it's personalized for an specific user, run it for every user that requests it.
Example of a query (in natural language): "Select all items that are cheaper than 15 dollars and are designed for the gender of the user X"
I don't know if there is a better way to do that. I wonder how Spotify work with their personalized and custom lists (like Discovery Weekly, Running Musics, Sleepy Monday et cetera).
Should I use a query string and store it on an attribute inside this object on my model? Should I do all of that without an object model (on the fly)? What are the best options? How big companies do that?

How to save user specific arrays in Mailchimp

For quite a while I am struggling with how to save custom user specific arrays of data in Mailchimp.
Simple example: I want to save the project ids for a user in Mailchimp and in best case be able to use them there properly as well. Let's say user fritz#frey.com has the 5 project ids 12345, 25345, 21342, 23424 and 48935. Why is there no array merge field that let's me save this array of project ids to a user?! (Or is there one and I am just blind...)
I know I can do drop down fields to put users in multiple groups, like types of projects for example, but the solution can hardly be a drop down with all (several thousand) project ids and I check the ones the user is a part of (and I doubt that Mailchimp would support that solution for a large number of group items anyways).
Oh and of course I could make the field myself by abusing a string field and connect the project ids with commas or a json string but that seems neither like a clean solution nor could I use the data properly in Mailchimp (as far as I know).
I googled quite a bit and couldn't find anything helpful sadly... :(
So? Can anybody enlighten me? :)
Thanks for all your help!
It sounds like you have already arrived at the correct answer: there is no "array" type, other than the interests type, which is global and not quite the same as an array.
The best solution here sort of depends on your data. If each project ID will have many different subscribers attached to it, and there won't be too many of them active at any given time, I'd just use interests. If you think there may be dozens of project ids active simultaneously, I'd not store this data on the subscribers at all, instead I'd build static segments for each project, and add users to them.
If projects won't have a bunch of subscribers associated, I'd store the data on your end and/or continue using the comma-separated string field.

Cheap way of modeling friend relationships

I have an app engine project (java) which has a User class. I'd like to model a cheap friend relationship system. Each user can have max 50 friends. I am thinking of doing something zany like:
class User {
String username;
Text friends; // "joe,mary,frank,pete"
}
Where "friends" is a comma delimited list of usernames that the user is friends with. Here are the operations I want to support and how I'd do them with the above:
Fetch my full friend list
Just look up the User object, return back the comma delimited list of friends.
Add a friend
Fetch my user object, check if the target name exists in the string, if not, append to the end. Persist modified User object back to data store.
Delete a friend
Fetch my user object, check if the target name exists in the string, if it does, delete it from the string. Persist modified User object back to data store.
Are two users mutual friends
Fetch both user objects, check that the usernames appear on one another's user object.
Getting a full list of friends is pretty important for my application, and storing each relationship as a separate entity seems nightmarish to me (fetching each entity from the datastore when a user needs to see their friends list would probably bankrupt me). I am hoping that a simple read from the Text attribute would be much more lightweight.
Checking for the mutual friend scenario seems like the biggest drawback here, but won't happen that often. I don't know if fetching the two User objects from the datastore and doing the string comparisons would be disastrous performance-wise. Might be ok? I think I may have also read that creating and deleting objects from the data store costs more than just modifying an existing object. So the add/delete friend operations might be better this way too.
Would be happy to hear any thoughts on this or more optimal ways of going about it.
Thank you
-------------------------- Update ---------------------
As per Adrian's comment, I could also do the following:
class User {
String username;
List<String> friends;
// or //
Set<String> friends;
}
So I think if I use a List, those entities will get indexed by default. I'm not sure if I could execute a GQL query knowing that the lists are indexed to get a match without actually fetching any entities. Something like:
SELECT COUNT FROM User WHERE
(username = "me" && friends = "bob") &&
(username = "bob" && friends = "me")
Storing as a Set would help do the search faster if I loaded both User objects, but I think for both the List and Set, extra time has to be taken to deserialize them when fetched from the datastore, so not sure if their benefits are negated. Maybe it would hurt more than it'd help?
I would actually suggest you store the data in two forms. First, a list of the usernames, and secondly, a matching list of datastore keys for those users' own entities.
This will allow you to both quickly display a user's friends, and look up one particular friend to check for a mutual relationship. In particular, it will almost certainly be more efficient to check the friend's list of friend keys for the original user's keys than to match on a string.
The only drawback will be keeping the two lists in sync, but given your list of operations that doesn't sound too hard.
List<String> friends; is a good solution and one that I've seen in professional use. If friends have User IDs of your app or google you can use that data type for a list of keys instead.

Another database table or a json object

I have two tables: stores and users. Every user is assigned to a store. I thought "What if I could just save all the users assigned to a store as a json object and save that json object in a field of a store." So in other words, user's data will be stored in a field instead of it's own table. There will be around 10 people to a store. I would like to know which method will require the least amount of processing for the server.
Most databases are relational, meaning there's no reason to be putting multiple different fields in one column. Besides being more work for you having to put them together and take them apart, you'd be basically ignoring the strength of the database.
If you were ever to try to access the data from another app, you'd have to make yourself go through additional steps. It also limits sorting and greatly adds to your querying difficulties (i.e. can't say where field = value because one field contains many values)
In your specific example, if the users at a store change, rather than being able to do a very efficient delete from the users table (or modify which store they're assigned to) you'd have to fetch the data and edit it, which would double your overhead.
Joins exist for a reason, and they are efficient. So, don't fear them!

Resources