I'm writing an Android app which uses Firebase realtime database. It's the first time I've used any Firebase products so it's been quite a learning curve so far, with already multiple data structure changes as the app develops and I learn more best practice.
I understand I should avoid nesting data wherever possible so at the moment I have my data stuctured like so;
{
"projects" : {
"jyZdNutWvUbA4XrQ3Gbb17rByyA2" : {
"-KcAq7Cx7wQL99_3Jo9l" : {
"area" : "R",
"dateCreated" : 1486257427801,
"dateModified" : 1486257427801,
"latitude" : 999.9,
"location" : "R",
"longitude" : 999.9,
"weather" : "R"
},
"-KcAqACaNOHSELyNfSu4" : {
"area" : "A",
"dateCreated" : 1486257440065,
"dateModified" : 1486257440065,
"latitude" : 999.9,
"location" : "A",
"longitude" : 999.9,
"weather" : "A"
}
}
}
}
I have a projects node which will store all the project data, then the unique userid child nodes (only 1 user in the above snippet) where each users projects are stored, then the unique projectid (2 projects in the above example) and finally all the details of a specific project. The idea being the app will just need to nvaigate to the apllicable userid and pull all children from there.
I have since decided I would like to add the ability to share a project with another user. I found this post (example code below if I implemented in my scenario) which seem's to do pretty much what I want, but I worry it will be less efficient as surely now I will need to scan all projects and dig an additional child deep (assuming I use the exact schema detailed below) before being able to check against rules as to whether a particular user is the owner or is allowed to read/write?
{
"projects" : {
"-KcAq7Cx7wQL99_3Jo9l" : {
"area" : "R",
"dateCreated" : 1486257427801,
"dateModified" : 1486257427801,
"latitude" : 999.9,
"location" : "R",
"longitude" : 999.9,
"weather" : "R",
"owner" : ""jyZdNutWvUbA4XrQ3Gbb17rByyA2",
"shares" : {
"uid" : "true"
}
},
"-KcAqACaNOHSELyNfSu4" : {
"area" : "A",
"dateCreated" : 1486257440065,
"dateModified" : 1486257440065,
"latitude" : 999.9,
"location" : "A",
"longitude" : 999.9,
"weather" : "A"
"owner" : ""jyZdNutWvUbA4XrQ3Gbb17rByyA2",
"shares" : {
"uid" : "true"
}
}
}
}
Additionally, many example data structures I have come across tend to store the data in a similar fashion to the second code snippet, i.e;
projects/projectid/userid whereas at the moment I have projects/userid/projectid which to me looks more efficient as you don't need to dig into each project to check if you have access to read/write. Am I misunderstanding the concept of how it works with my methodology?
The doubt the app is going to be huge with regards the database so I guess performance won't really be impacted that much regardless of my structure, but I do like to adhere to best practices wherever possible.
Related
Suppose I have a Firebase database in my Android App and structured as below:
{"firebase_db" : {
"users" : {
"user_uid_0" : {
"name" : "name_0",
"score" : 2000
},
"user_uid_1" : {
"name" : "name_1",
"score" : 3000
},
"user_uid_2" : {
"name" : "name_2",
"score" : 1000
},
"user_uid_3" : {
"name" : "name_3",
"score" : 4000
},
"user_uid_4" : {
"name" : "name_4",
"score" : 0
}
}
}
}
and I would like to sort them by the child "score". However, I do not want an entire list as the return (which can be easily achieved using the orderByChild() and limitToLast() methods). Instead, I want to know at what place a specific node is when ranked by the child "score" in descending order. For example, if I give the input "user_uid_0", then it should return 3 (the 3rd place); if the input is "user_uid_2", then it should return 4 (the 4th place)
But, I could not find a way to achieve this in several lines of code. Until now, the only way I've come up with to solve this problem efficiently was write a cloud function on Firebase... Is there any simpler way to do this?
Yes, you can solve this on user side. The simplest way I can think of is to query the database according to your needs to get all user objects. Add all this objects to a map, in which the key of the map is the user id and the value is the position. In the end, just iterate over the map and get the position according to your user id. That's it!
I am trying to parse the very large JSON file (for me around 100MB, ~4 million lines) that you receive when downloading your personal location history from Google Takeout and put in a local database in an Android application.
The structure of the JSON file looks like this, and I put a very small sample on Pastebin to show the structure.
{
"locations" : [ {
"timestampMs" : "1518722738911",
"latitudeE7" : 123456789,
"longitudeE7" : 123456789,
"accuracy" : 21
}, {
"timestampMs" : "1518722617339",
"latitudeE7" : 123456789,
"longitudeE7" : 123456789,
"accuracy" : 21,
"activity" : [ {
"timestampMs" : "1518722603634",
"activity" : [ {
"type" : "TILTING",
"confidence" : 100
} ]
}, {
"timestampMs" : "1518722660455",
"activity" : [ {
"type" : "STILL",
"confidence" : 55
} ]
} ]
} ]
}
When parsing this in Java with GSON, you will get a LinkedTreeMap. I know that GSON is not the fastest parser out there, but that is another issue.
The purpose of storing all the JSON data into a SQLite database is to have it available much faster and analyze it, so I would like to have the data as practical as possible.
I tried creating two separate tables, one for simple timestamps and their longitude and langitude, and one for the activities associated with timestamps themselves.
However, I can't quite wrap my head around of how to iterate through this TreeMap correctly, converting those entries into simple rows, since it's quite a mess with many subarrays.
Is SQLite even the right datbase, or should I use something else for this kind of data? How would you parse such a file?
Any tip or suggestion is very much appreciated, thanks.
You could use http://www.jsonschema2pojo.org/ which converts Json to Pojo automatically.
I wanted to try NoSql and started my project in Firebase. My app's data has increased a lot. However, now I need to run a country-specific app and hence show/filter data according to countries in my app.
The structure of my current data is as follows.
{ clients: {
"04E2LBixKoVn9sGzRvxtMoC7MsF3" : {
"clientName" : "Rising Mall",
"contact" : {
"branches" : {
"-Kx6QoVhr0WpDQ3i68_n" : {
"address" : "Test Location",
"phone" : "999999999",
"country": "USA"
}
},
"mail" : "test#test.edu.np",
"website" : "http://www.test.np"
},
"description" : "Test Description."}
},
"073ezb0UsgetSef0lwk50dhogjM2" : {
"clientName" : "Leather Craft",
"contact" : {
"branches" : {
"-Kx6QoVj_QKM7tjekh_1" : {
"address" : "Test Location",
"phone" : "888888888"
"country": "UK"
}
},
"mail" : "test#test.com",
"website" : "https://www.test.com"
},
"description" : "Test"
}
}
From the above structure, I want to get a list of all the clients whose country is "USA". How can I do it directly by querying FirebaseDatabase in Android? Is it possible? Or do I have to change the structure of my database completely? If I have to restructure my database do suggest a solution to that as well.
UPDATE
I took the suggestion given by #alex-mamo and designed all my structures by denormalizing the data.
Firebase-root
|
--- usClients
|
--- usClientId1 : true
|
--- usClientId2 : true
To achieve this, you don't need to restructure your database entirely, you just need to change it a little bit. To solve this problem, you need to add another node to your database named usClients. Every time you add a new user which is from USA, add it also in this new created node. Your new node should look like this:
Firebase-root
|
--- usClients
|
--- usClientId1 : true
|
--- usClientId2 : true
Whith this structure you can query your database to get only the clients within USA. This can be done attaching a listener on usClients node and iteration on the DataSnapshot object.
This practice is called denormalization and is a common practice when it comes to Firebase. For a better understanding, i recomand you see this video, Denormalization is normal with the Firebase Database.
"news" : {
"-KnLRSIOyD7HgldFGty" : {
"caption" : "some grounds",
"content" : "some contents",
"created_on" : 1498246403444,
"newspaper_id" : "-KnLPu2N5039ZbqS",
"status" : false,
"thumbnail" : "thumbnail/1498254125498",
},
}
"newspapers" : {
"-KnLRSIOyD7HgldFGty" : {
"logo" : "logo/1498245996906",
"paper_name" : "NewsOnline"
},
}
I want to filter firebase to do something like this.
mDatabaseRef.child("news").orderByChild("newspaper_id").equalTo(id).orderByChild("status").equalTo(false);
Since multiple orderBy() will throw exception in firebase, what is the other way to achieve the filter.
Currently Firebase supports only a single orderBy per query.
So if you want to filter or order the results on more than one property (2 query in your case), you'll either have to do the additional filtering (or ordering) client-side in your Android code or you'll have to come up with your own indexing scheme that combines the properties.
In your case i suggest you add a new child named newspaperId_status which can get the value as concatenation of both values like this:
newspaperId_status: -KnLPu2N5039ZbqS_false
In this way you can query all newspappers which have the status of false.
Hope it helps.
I've been searching for different examples but unable to find proper solution for my firebase nodes. I have 3 nodes 1 for Question ,Second node contains Answers of questions and 3rd node contains Comments on that Answer.!
How I will be Able to perform query using firebase
I've been searching for different examples but unable to find proper solution for my fire base tables. I have 3 nodes
Questions
Answers
Comments on Answers
How I will be Able to perform query using firebase (Join based Concept Implementation)
mdatabaseReference.child("Answer").equalTo(QID);
how I will be able to get Answers of specific Question and Comments on that Answers.!
here is My JSON
{
"Answer" : {
"f40357b1-d1f5-4b7a-98ec-54d9e7b2e518" : {
"dateTime" : "16 Mar 2017 15:30:29",
"professorAnswer" : "Hezbollah is an Islamist religious organization founded in 1985 and based in Lebanon. It follows Shi'Islam (also called Shi'ite Islam), the second largest denomination of Islam. Shi'a Muslims follow the teachings of the prophet Muhammad, a direct descendant of Isma'il (the first son of Ibrahim/Abraham).Contd.!",
"professorId" : "7ceef713-eb59-4db4-a8d2-21d5a01eedfc",
"questionId" : "fd2a34a0-e7d9-4b2c-8192-59705df827c2"
}
},
"comment" : {
"29192e3a-a013-4fcc-9859-1f5cc62464cb" : {
"commentText" : "ORGANIZATION hezbollah bases on the bible but their goals is to save people in pagans work!",
"dateTime" : "16 Mar 2017 15:30:52",
"AnswerId" : "f40357b1-d1f5-4b7a-98ec-54d9e7b2e518"
"questionId" : "fd2a34a0-e7d9-4b2c-8192-59705df827c2",
"userId" : "bXCeW6jfidbHuMCCCMkDGWcGZRS2"
}
},
"questions" : {
"41c454a8-fab6-4e41-9093-b1120ffd1be0" : {
"description" : "I know they're a Islamic organization but where are they based? What are their goals?",
"idQuestion" : "fd2a34a0-e7d9-4b2c-8192-59705df827c2",
"time" : "16 Mar 2017 15:30:12",
"title" : "What are the aims of the religious organization Hezbollah?",
"user_id" : "bXCeW6jfidbHuMCCCMkDGWcGZRS2",
}
},
"user" : {
"13bd37e5-fc87-4468-a89e-7cb4ecaab05f" : {
"email" : "email#gmail.com ",
"user_id" : "bXCeW6jfidbHuMCCCMkDGWcGZRS2"
}
}
The problem is that I want to filter those events... like for example, using .orderByChild("Answer").equalTo(QID) maybe it's wrong query but it is just for concept to get just the Answers for a given Question ID and then populate my List with it.
The right way to do this is to get every data separately, I don't know perfectly how your data are organized but this may be an appropriate solution:
// Gets the Question with id = QID
mdatabaseReference.child("Questions").child(QID);
// Gets the Answers for that question
mdatabaseReference.child("Answers").child(QID).once("value", function(answers) {
// For every Answer gets the comments
for(var answerID in answers) mdatabaseReference.child("Comments").child(QID).child(answerID);
});
EDIT: To use Firebase efficently you should structure your data depending on how you want to retrieve them. If you want to get all the answers for a given question I suggest you to use this data structure:
{
"Answers": {
"questionID": {
"answerID": {
"dateTime" : "16 Mar 2017 15:30:29",
"professorAnswer" : "Hezbollah is an Islamist religious...,
"professorID" : "...",
"questionID" : "..."
}
}
}
}
so that you can get your data for a given questionID this way:
mdatabaseReference.child("Answer").child(questionID).once('value', function(answers) {
// answers contains all the answer for the question with ID == questionID
});
NOTE: You don't have tables in Firebase, everything is JSON Object
There In No Concept of Joins In fireBase.Its noSql ..All you need to do is Query On According to Question Id and then in answer id check for question id..and same thing goes for comments it will be a nested EventBased search.!