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.
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:
Updating a field contains period (.) is not working as expected.
In docs, nested fields can be updated by providing dot-seperated filed path strings or by providing FieldPath objects.
So if I have a field and it's key is "com.example.android" how I can update this field (from Android)?
In my scenario I've to set the document if it's not exists otherwise update the document. So first set is creating filed contains periods like above and then trying update same field it's creating new field with nested fields because it contains periods.
db.collection(id).document(uid).update(pkg, score)
What you want to do is possible:
FieldPath field = FieldPath.of("com.example.android");
db.collection(collection).document(id).update(field, value);
This is happening because the . (dot) symbol is used as a separator between objects that exist within Cloud Firestore documents. That's why you have this behaviour. To solve this, please avoid using the . symbol inside the key of the object. So in order to solve this, you need to change the way you are setting that key. So please change the following key:
com.example.android
with
com_example_android
And you'll be able to update your property without any issue. This can be done in a very simple way, by encoding the key when you are adding data to the database. So please use the following method to encode the key:
private String encodeKey(String key) {
return key.replace(".", "_");
}
And this method, to decode the key:
private String decodeKey(String key) {
return key.replace("_", ".");
}
Edit:
Acording to your comment, if you have a key that looks like this:
com.social.game_1
This case can be solved in a very simple way, by encoding/decoding the key twice. First econde the _ to #, second encode . to _. When decoding, first decode _ to . and second, decode # to _. Let's take a very simple example:
String s = "com.social.game_1";
String s1 = encodeKeyOne(s);
String s2 = encodeKeyTwo(s1);
System.out.println(s2);
String s3 = decodeKeyOne(s2);
String s4 = decodeKeyTwo(s3);
System.out.println(s4);
Here are the corresponding methods:
private static String encodeKeyOne(String key) {
return key.replace("_", "#");
}
private static String encodeKeyTwo(String key) {
return key.replace(".", "_");
}
private static String decodeKeyOne(String key) {
return key.replace("_", ".");
}
private static String decodeKeyTwo(String key) {
return key.replace("#", "_");
}
The output will be:
com_social_game#1
com.social.game_1 //The exact same String as the initial one
But note, this is only an example, you can encode/decode this key according to the use-case of your app. This a very common practice when it comes to encoding/decoding strings.
Best way to overcome this behavior is to use the set method with a merge: true parameter.
Example:
db.collection(id).document(uid).set(new HashMap<>() {{
put(pkg, score);
}}, SetOptions.merge())
for the js version
firestore schema:
cars: {
toyota.rav4: $25k
}
js code
const price = '$25k'
const model = 'toyota.rav4'
const field = new firebase.firestore.FieldPath('cars', model)
return await firebase
.firestore()
.collection('teams')
.doc(teamId)
.update(field, price)
Key should not contains periods (.), since it's conflicting with nested fields. An ideal solution is don't make keys are dynamic, those can not be determined. Then you have full control over how the keys should be.
May I ask if there is any implementation to collect the time when the first data is updated. For example, there is a queue function in my app. When an user has taken the queue ticket, Firebase will then be updated.
Therefore, I would like to know the time that the first user in the queue.
Is there any code for this in Android Studio? Many thanks!!
The Firebase Database does not store metadata (informations like the timestamp) for CRUD operations that are performed. Because of that, you need to store this kind of data yourself by creating your own mechanism.
In fact, you need to create a new field for each child you want to trace and change the value of the timestamp every time a action is performed. The best practice within a Firebase database is to save your data as a timestamp using: ServerValue.TIMESTAMP.
Note, that when you are saving the timestamp, you are saving as a Map and when you are retrieving, you are retrieving it as a long.
To set the timestamp, I recommend you to use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Map<String, Object> map = new HashMap<>();
map.put("timestamp", ServerValue.TIMESTAMP);
rootRef.child("yourNode").updateChildren(map);
To get you data back, I recommend you using the following method:
public static String getTimeDate(long timeStamp){
try{
DateFormat dateFormat = getDateTimeInstance();
Date netDate = (new Date(timeStamp));
return dateFormat.format(netDate);
} catch(Exception e) {
return "date";
}
}
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.
My model is like:
public class MyModel{
private String mId;
private String mName;
T mAnObject;
}
How can I store T object in database.
If you need to save specific properties, just do that, otherwise you could serialize it to JSON, as an option (as demonstrated here).
Example:
Object myObj has three properties: String title, String subtitle, String text
1 - You can save them as separate database rows and then when you read from the database you recombine them to create your Object.
2 - You can also use Json to save the properties, this way you only need to store a single String in the database and when you read from the database convert the Json String to your Object.