I need some advice on how to structure my database in order to query it correctly. From what I've understood the structure of the database is everything, but I am not sure I am using it correctly.
Basically my app is supposed to retrive data from an api and display that in a listview. Every item (newspost) in the listview can have comments from firebase users.
So I have "NewsPost" , "User" and "Comment" models that looks like this.'
NewsPost.class
private String id;
private String date;
private String title;
private String commentsNumber;
private List<Comment> comments;
private String imageUrl;
User.class
private String userName;
private String userAvatar;
private String firstName;
private String lastName;
private String eMail;
Comment.class
private UUID uuid;
private String postId;
private String message;
private String postDate;
private String userAvatar;
private String userName;
So this is how I tried to store it:
AND this is how I try to get the comments when a user clicks to read the comments for the specific newsPostItem in the listView with the newsPostId as a query param.
public void getComments(String postId) {
comments = new ArrayList<>();
Query query = databaseReference.child("comments").orderByChild(postId).equalTo(postId);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot issue : dataSnapshot.getChildren()) {
Comment comment = issue.getValue(Comment.class);
comments.add(comment);
}
Log.d("GETCOMMENTS", "SNAPSHOT EXISTS");
view.onCommentsLoaded(comments);
}
else{
view.onCommentsLoaded(comments);
Log.d("GETCOMMENTS", "SNAPSHOT NOT EXISTS");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
view.onCommentsLoaded(comments);
Log.d("GETCOMMENTS", databaseError.getMessage());
}
});
}
My Question is, amidoinitrite?
I got a firebase downloaded limit for this month warning (10 GB) which shouldn't happen because I am the only user right now.
Any help is appreciated!
Sidenote: The userAvatar is stored in a byte[] in the database, no good?
When using Firebase, there are a few rules that we need to keep in mind. In your particular case, i recomand you using denormalization and to change the database to be as flatten as possible. For a better understanding, i recomand you see this video, Denormalization is normal with the Firebase Database. Because Firebase Realtime Database cannot query over multiple properties, it ussaly involves duplication data. So this things are normal when it comes to Firebase. In your particular case, i recomand you doing both things.
I also recomand you read this post, Structuring your Firebase Data correctly for a Complex App. It's very well explained and will help you take the best decision.
You need to know that there is no perfect sturcture for a database. You need to structure your database in a way that allows you to read/write data very easily and in a very efficient way. If you don't know yet, Firebase has launched a new product named Cloud Firestore. Realtime Database does not scale automatically while the new Firestore does.
Currently you are adding "NewsPostID" as root node inside "comments".
This structure will consume more storage size because every new comments is added as new root inside "comments" node.
Suppose we wants to query that : Specific user's all comments for any single date. so, in this case current structure is complex to apply query.
You can change structure like :
"comments"
-"userEmail"
- "NewPostDate"
- "NewpostID:15478"
-KHZzTwazaSd (this is random id)
-"message: hey.."
-"postDate: Date + 12:10PM"
-KHZzTwazaSd (this is random id)
-"message: Nice post.."
-"postDate: Date + 12:22PM"
- "NewpostID:54478"
-KHZzTwazaSd (this is random id)
-"message: Nice day"
-"postDate: Date + 10:45PM"
You can get all user related details from user table using "userEmail" from "comments". this will decrease node size and also will be helpful to query.
Related
I wanted to add a string values to a realtime firebase database with the firebase UID being the name and the string being the value. When I use the below code it makes the UID a parent node and set the value to a child node.
ReferralCode referralCode = new ReferralCode(refCode); databaseReference.child("referralCodes").child(userId).setValue(referralCode);
I wanted the values to be populated as the second one. But with the above code,i get the first result. I'm going to search for the referral codes afterwards,so i think it would be faster if the values are populated as the second one to avoid accessing a child node which will be time consuming for large database entities.
When you are using a Model like you created ReferralCode and using it to with .setValue(referralCode) then Firebase will automatically create it as the child with attributes your ReferralCode.java has. Example below:
public class Restaurant {
private int code;
private int type;
private String name;
}
So if I create a variable Restaurant tempRest = new Restaurant(111, "Restoran DM", 0) and use it like this:
database.child("restaurants").child("1st restaurant").setValue(tempRest);
Firebase will create something like this:
restaurants
1st restaurant:
code: 111
name: "Restoran DM"
type: 0
But if you use String in setValue() like this:
String someValue = "some value";
database.child("restaurants").child("awpjawpdaw").setValue(someValue);
it will give you what you want. Example, I used this:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
String refCode = "1231231";
database.child("restaurants").child("wadawdapwodawp").setValue(refCode);
and here is what happened in database:
I'm making an app and retrieving data for profile like name, age, username, dob, etc., from a firebase database. But, when I open the app and go to the profile page, it takes about 2 to 3 seconds to refresh the text there and then display the data. I want to make that process faster. Is there anyway to do that? And is it possible to store that data within local storage of the app and display it and update that stored data later using internet and data from firebase database? The same principal I wanted to apply to images which load from firebase storage. Those take much longer than the data. Approximately 4 to 5 seconds.
This is what I'm currently using:
mDatabase = FirebaseDatabase.getInstance().getReference().child(current_user);
mDatabase.keepSynced(true);
mDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String first = dataSnapshot.child("firstname").getValue().toString();
String last = dataSnapshot.child("lastname").getValue().toString();
String friend = dataSnapshot.child("friends").getValue().toString();
String post = dataSnapshot.child("posts").getValue().toString();
String user = dataSnapshot.child("username").getValue().toString();
String db = dataSnapshot.child("age").getValue().toString();
String ag = dataSnapshot.child("dob").getValue().toString();
String bo = dataSnapshot.child("bio").getValue().toString();
String rela = dataSnapshot.child("relationshipstatus").getValue().toString();
firstname.setText(first);
lasttname.setText(last);
username.setText(user);
friends.setText("Friends:"+friend);
posts.setText("Posts:"+post);
dob.setText("DOB:"+db);
age.setText("Age:"+ag);
bio.setText(bo);
relation.setText(rela);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Whenever you're storing user profile in firebase first store it in local, use shared preference or room whichever suits you more, and after that whenever you do any update, first do it in local data and then sync it to firebase storage, that way the data will always be their with you until user clears it.
For this always make a check whether local data exists, if it doesn't get data from firebase storage then save it in local.
Same way use caching for storing images in local, use glide or fresco for imageloading, then add simple code for caching, so until image url changes or local data is deleted you'll always get image very fast.
I have this structure in my Database inside the UserID I have this random ID which I declared when adding data to database I don't know how to call that to display the info inside to recycler view. Actually I can display the info in Recyclerview if the declared pushid is not there but I need that push ID to work on other modules. I am still learning so I get easily confused with this kind of thing. Any help would be so much appreciated.
This is the line which is calling the table.
mToolsDatabase = FirebaseDatabase.getInstance().getReference().child("toolHistory");
mToolsDatabase.child(list_user_id).child(mCurrentUser.getUid()).addValueEventListener(new ValueEventListener(){
public void onDataChange(DataSnapshot dataSnapshot) {
final String toolName = dataSnapshot.child("name").getValue().toString();
final String toolUser = dataSnapshot.child("user").getValue().toString();
final String toolBorrow = dataSnapshot.child("dateTimeBorrowed").getValue().toString();
final String toolReturn = dataSnapshot.child("dateTimeReturn").getValue().toString();
final String toolStatus = dataSnapshot.child("status").getValue().toString();
final String toolId = dataSnapshot.child("logId").getValue().toString();
viewHolder.setName(toolName);
viewHolder.setUser(toolUser);
viewHolder.setDateTimeBorrowed(toolBorrow);
viewHolder.setDateTimeReturn(toolReturn);
viewHolder.setStatus(toolStatus);
viewHolder.setLogId(toolId);
}
Firebase has its inbuilt method FirebaseRecyclerAdapter for display items in RecyclerView
Also, you can follow this link for more info
https://grokonez.com/android/firebase-realtime-database-display-list-of-data-firebaserecycleradapter-android-development
I want to save the data in firebase database with a descending order and I found that the solution is to add a timeStamp field with a negative value, but using ServerValue.TIMESTAMP save only the value in a positive way,so how can I save a negative timeStamp in my FireBase :
Code of model:
public class Book{
Object createdTimestamp;
String nom_livre;
String desc_livre;
String prix_livre;
String id_book;
String id_user;
public Book() {
super();
}
public Book(String nom_livre, String desc_livre, String prix_livre, String id_book,String id_user, Object createdTimestamp) {
super();
this.nom_livre = nom_livre;
this.desc_livre = desc_livre;
this.prix_livre = prix_livre;
this.id_book = id_book;
this.id_user=id_user;
this.createdTimestamp= createdTimestamp;
}
#Exclude
public long getCreatedTimestampLong(){
return (long)createdTimestamp;
}
//other getters and setters
}
Code of adding data in fireBase , im my case I'm creating a Book on addBookActivity:
private void createBook(String nom_livre, String desc_livre,String prix_livre,Object createdTimestamp) {
bookInfos=new Book(nom_livre,desc_livre,prix_livre,idLivre,id, ServerValue.TIMESTAMP );
myRefBook.child(idBook).setValue(bookInfos);
}
You have two options, and they both require a second write to the database after you initially write the regular timestamp number as a positive number.
If you only want to write data on the client app, what you can do is write your createdTimestamp as you are right now, then read that value back into the client by listening to the location that you just wrote. After you read it back in, you'll have the actual timestamp value. Then, you can easily compute the negative it and write it back where you want it (maybe revCreatedTimestamp, if you're using it to sort in reverse chronological order).
Your other option is to use Cloud Functions for Firebase to write a Realtime Database trigger to respond to writes that match the location /books/{book_id} where book_id is that string you're generating for the book. That trigger can then capture the timestamp and write back the negative version at the same location.
I am currently using Sugar ORM and Android Async Http Client for my Android application.
I read through the documentation of Sugar ORM and did exactly what is written there.
My HttpClient is using the singleton pattern and provides methods for calling some APIs.
Now comes the bad part about it. I am not able to save the data persistently into my database which is created by Sugar ORM.
Here is the method, that is calling an API:
public void getAvailableMarkets(final Context context, final MarketAdapter adapter) {
String url = BASE_URL.concat("/markets.json");
client.addHeader("Content-Type", "application/json");
client.addHeader("Accept", "application/json");
client.get(context, url, null, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
Log.i(TAG, "Fetched available markets from server: " + response.toString());
Result<Markets> productResult = new Result<Markets>();
productResult.setResults(new Gson().<ArrayList<Markets>>fromJson(response.toString(),
new TypeToken<ArrayList<Markets>>() {
}.getType()));
ArrayList<Markets> marketsArrayList = productResult.getResults();
// This lines tells me that there are no entries in the database
List<Markets> marketsInDb = Markets.listAll(Markets.class);
if(marketsInDb.size() < marketsArrayList.size() ||
marketsInDb.size() > marketsArrayList.size()) {
Markets.deleteAll(Markets.class);
for(Markets m : marketsArrayList) {
Markets market = new Markets(m.getId(), m.getName(), m.getChainId(), m.getLat(),
m.getLng(), m.getBusinessHourId(), m.getCountry(), m.getZip(), m.getCity(),
m.getStreet(), m.getPhoto(), m.getIcon(), m.getUrl());
market.save();
adapter.add(market);
}
adapter.notifyDataSetChanged();
}
List<Markets> market = Markets.listAll(Markets.class);
// This lines proves that Sugar ORM is not saving the entries
Log.i(TAG, "The market database list has the size of:" + market.size());
}
});
}
This is what Logcat is printing:
D/Sugar: Fetching properties
I/Sugar: Markets saved : 3
I/Sugar: Markets saved : 5
I/RestClient: The market database list has the size of:0
Also I took a look at the Sugar ORM tag here at stackoverflow, but no answers or questions could give me a hint on how to solve that problem.
I am a newbie to the android ecosystem and would love any help of you guys to solve this problem.
Thanks in advance
I just solve it the same problem as you have.
It was a pain in the neck but after few hours I find out what caused this problem.
Using Sugar ORM you must not set id property as it's belongs to SugarRecord class,
otherwise ORM will try to update objects instead of insert them.
As I need to have field with my object id, I used json annotation to assign it to another field.
Last step was configure GSON to exclude fields without Expose annotation.
So my class looks like one below now:
public class MyClass
{
#Expose
#SerializedName("id")
private long myId;
#Expose
private String field1;
#Expose
private String field2;
#Expose
private byte[] field3;
#Expose
private double field4;
public MyClass() { }
// parametrized constructor and more logic
}
Cheers!