How to build structured realtime firebase database for iOS, swift? - ios

I am currently setting up my realtime firebase database to my iOS application.
It is my first time trying to structure user data in a firebase database, and I am really, really struggling with understanding a few key things.
A bit of context to my application's database needs:
When a new user is created, the attributes assigned directly to the user are:
Age
Email
Username
Nationality
Later on, the user needs the option of creating personal diaries!
Each of these diaries being arrays/lists of objects... Where each object in a diary furthermore holds a few attributes in a list/array.
After reading everything I could find anywhere, I picture my database something like this:
I am terribly sorry if it becomes too specific - I will try to make the question as open as possible:
My question is:
How to create the different "children" programmatically and how to find the keys leading back to them, so I can refer to them at other times again? (when editing an attribute in a child).
A few methods I have tried:
setValue([ArrayOfObjects]) --> This creates the desired array, but I can't seem to find e.g. index 3 in this array, to allow user to change his/her email later on.
childByAutoID() --> This as well creates my array, but gives several other problems: User can only store one diary, still can't find the paths to specific indexes...
setValue(), andPriority() --> Can't seem to make the priority function. (Is this function also outdated??)
And a few more...
If anyone can tell me how to achieve just the first few steps in setting up my database structure, I will be forever grateful - I have spent literally all day on it and I am not moving forward ...
Or, at least tell me, if I am on the right track regarding my desired setup of the database. Is it flat enough? Is there a smarter way to store all these user created lists?
Thank you so much! :-)

I don't know Swift so my examples are in Dart but the methods are similar I believe.
First off, I would split the Users node into two. One to hold the user data, which is normally pretty static, and the other to hold the diaries. You would use the same uid key as reference to both. This way you have less nesting to worry about and therefore it is much easier to CRUD the data. If you are using Firebase to authenticate your users then I would use the unique key that Firebase creates for each user as the keys for these two nodes.
Then...
To create a user data node record the Dart code would be something like:
referenceUserData.child(<authenticated user id>).set({
"age": <age value>,
"email": <email value>,
"name": <name value>,
});
To create a user diary node object record the Dart code would be something like:
referenceUserData.child(<authenticated user id>).child(<diary key>).child(<diary object key>).set({
"object info value 1": <object value>,
"object info value 2": <object value>,
"object info value 3": <object value>,
});
You could also create all the object records at once by writing them as a List (array) using .set().
You also need to decide what your diary key should be. You could use Firebase to generate a unique key by using .push().set().
To read eg. the user data then your call could be:
referenceUserData
.child(<authenticated user id>)
.once()
.then(
(DataSnapshot snapshot) {
print(snapshot.key);
if (snapshot.value != null) {
print(snapshot.value);
<code to process your snapshot value>
}
};
BTW, 'priority' is legacy from the early days of Firebase RTDB so I wouldn't try to use it.

Related

Dexie eachUniqueKey and Where Clause

I'm developing an application in Quasar/Electron and using Dexie/IndexedDB for my database. I want to find all distinct records in the database that contain both my Event ID and a Dog ID (both key indexed fields). I am able to do this with the following code:
await myDB.runTable
.orderBy('[fk_event+fk_dog]')
.eachUniqueKey((theDuo) => {
this.runsArray.push({eventID: theDuo[0], dogID: theDuo[1]})
})
I'm using a combined key which is working well. However, I need to have more of the records than just the keys. I need a few more fields, is this possible?
I was trying to get records with the unique key function while also using the where function, but that doesn't seem to work.
I need to get all the unique (distinct?) dogs in the table that are in a particular event. And also get their corresponding information. I'm not sure if there is a better, more efficient way to do this? I can always pull out all the records and loop through them to build a custom array, I was just hoping to do this at the table read level. (yeah I'm still in tables/records even though these are collections etc. :p ).
Even the above code gives me all the events, and I can pull out what I need with a filter. I just was thinking it would be faster and more efficient to do it at the read level.
this.enteredRuns = this.runsArray.filter((theEvent) => {
return ( (theEvent.eventID == this.currentEventID) )
})
Try
await myDB.runTable
.orderBy('[fk_event+fk_dog]')
.clone({unique: "unique"})
.toArray()
I know this isn't documented but it should do the work to use unique cursor while still extracting the whole objects and not just the keys. You cannot combine with where but you could use .filter. Just be aware that not all records with be scanned as it will jump over records with same keys - selecting the first visited records only.

Firebase: Maintain a Username Directory

I am creating a Social app and want to track if a username already exists or not. The username list is supposed to grow in future and the way I was doing it now was a key value pair of <string,bolean> like this:
name1: true,
name2: true
all the above data was to be stored in a single document and whenever I want to see if a user exists I would call this document and check accordingly. But here's the problem, firebase max document size is 1MBs and as the users grow this can be problematic, so wanted to know from firebase experts that what's the best way to solve this use case in firestore or realtime database but since I need to query exists maybe realtime db won't suit that well.
Note that I don't want any of firestore querying capabilities but only to check if an entry exists in the record or not and if not just add it.
The Realtime Database doesn't have a 1MB limit (since it has no concept of a document, and everything is just a tree of JSON), so I'd typically use that for the index of user names.
Checking whether a name exists is pretty simple there too, and in JavaScript would look something like:
const usernames = firebase.database().ref('usernames');
usernames.child('name1').once((snapshot) => {
if (snapshot.exists()) {
...
}
});

Realm Swift: Question about Query-based public database

I’ve seen all around the documentation that Query-based sync is deprecated, so I’m wondering how should I got about my situation:
In my app (using Realm Cloud), I have a list of User objects with some information about each user, like their username. Upon user login (using Firebase), I need to check the whole User database to see if their username is unique. If I make this common realm using Full Sync, then all the users would synchronize and cache the whole database for each change right? How can I prevent that, if I only want the users to get a list of other users’ information at a certain point, without caching or re-synchronizing anything?
I know it's a possible duplicate of this question, but things have probably changed in four years.
The new MongoDB Realm gives you access to server level functions. This feature would allow you to query the list of existing users (for example) for a specific user name and return true if found or false if not (there are other options as well).
Check out the Functions documentation and there are some examples of how to call it from macOS/iOS in the Call a function section
I don't know the use case or what your objects look like but an example function to calculate a sum would like something like this. This sums the first two elements in the array and returns their result;
your_realm_app.functions.sum([1, 2]) { sum, error in
if let err = error {
print(err.localizedDescription)
return
}
if case let .double(x) = result {
print(x)
}
}

How to access object field in qaf step from stored variable

In my previous question I was looking for a way to access and store return value of the function in qaf step. I was provided with the following:
When create new user using "{'name':'user1','password':'user123'}"
And store into 'newUser'
Then system should have user '${newUser}'
Now, I'd like to know how to get value from object/collection stored.
If it is a simple object named newUser which has field Id. How would I pass Id on next step?
And, if return is List, how to get by index from stored list?
Resolved issue on my own. If anyone faces same unknowns, here is how I solved it.
For requirements to work around response data, parsing same stored objects in properties by specific fields or collecting data from other structures such as Maps or Lists, create common functions with #QAFTestStep annotation to get data for class member name, map by key or list by index and so on... Add those in common steps and then write stepname text in gherkin format with parameters specified. Let me know if someone needs help, always ready to help out...

Firebase rules to access specific child's value

The childByAutoId would be useful if you want to save in a node multiple children of the same type, that way each child will have its own unique identifier.
List:{
KJHBJJHB:{
name:List-1,
owner:John Doe,
user_id:<Fire base generated User_id>
},
KhBHJBJjJ:{
name:List-2,
owner:Jane Lannister,
user_id:<Fire base generated User_id>
},
KhBHJZJjZ:{
name:List-3,
owner:John Doe,
user_id:<Fire base generated User_id>
}
}
I am trying to access the List with the help of the following code:
let ref = FIRDatabase.database().reference(withPath: "/List")
The current user logged into the app is John Doe. When the user accesses the list, I want all the List child whose owner is John Doe(i.e. List-1 & List-3) and ignore the other child values.
Do I have to do this in my application or can this be achieved via Firebase Security rules?
My current rule definition is:
"List":{
".read": "root.child('List/'+root.child('List').val()+'/user_id').val() === auth.uid" }
But this rule is not giving me any success. Any idea how to achieve the desired result?
You're trying to use security rules to filter the list. This is not possible and one of the common pitfalls for developers coming to Firebase from a SQL background. We commonly refer to it as "rules are not filters" and you can learn more about it in:
the Firebase documentation
this answer
our new video series Firebase for SQL developers
and many previous questions mentioning "rules are not filters"
The solution is almost always the same: keep a separate list of the keys of posts that each user has access to.
UserLists:{
JohnUid: {
KJHBJJHB: true,
KhBHJZJjZ: true
},
JaneUid: {
KhBHJBJjJ: true
}
}
This type of list is often referred to as an index, since it contains references to the actual post. You can also find more about this structure in the Firebase documentation on structuring data.

Resources