I store a Date in Firestore. I get an HashMap<String, Object> from firestore and i want to recreate my object from it.
Before implementing the Date the working code was :
HashMap<String, Object> document = new HashMap<String, Object>();
document.put("name", "name");
JSONElement jsonElement = gson.toJsonTree(document);
Event event = gson.fromJson(jsonElement , Event.class);
I have now add the field
#ServerTimestamp
private Date dateOfEvent;
But when i try to serialize it i get the following error:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected STRING but was BEGIN_OBJECT at path $.dateOfEvent
Because the JsonElement "dateOfEvent" look like this because it's a Firestore Timestamp:
{"dateOfEvent": {"nanoseconds":0,"seconds":1584921600}, "name": "test Event"}
Thanks for your time and your help.
Gson is expecting a Date string like 2020-02-27T09:00:00 but it's actually an object. You could setup your classes like this and add a helper method to get dateOfEvent as a Date:
class Event {
private String name;
private MyDate date;
}
class MyDate {
private Long nanoseconds;
private Long seconds;
// getters/setters for nanoseconds, seconds...
public Date asDate() {
// convert to date
}
}
Related
In the past a manually created as list of data, which was stored locally in a database. Now I would like to parse those data and put them through import json option into firebase dbs, but what I get doesn't look like firebase generated json.
What I get is:
[
{
"id":"id_1",
"text":"some text"
},
{
"id":"id_2",
"text":"some text2"
},
...
]
what I want is something like this:
{
"id_1": {
"text":"some text",
"id":"id_1"
},
"id_2":{
"text":"some text2",
"id":"id_1"
},
...
}
my Card class
class Card{
private String id;
private String text;
}
retrieving data
//return list of card
List<Card> cards =myDatabase.retrieveData();
Gson gson = new Gson();
String data = gson.toJson(cards);
So how I can I achieve this (it looks to me) dynamically named properties for json that look like those generated by firebase ?
EDIT:
I found that gson has FieldNamingStrategy interface that can change names of fields. But it looks to me it's not dynamic as I want.
EDIT2
my temp fix was to just override toString()
#Override
public String toString() {
return "\""+id+"\": {" +
"\"text\":" + "\""+text+"\","+
"\"id\":" +"\""+ id +"\","+
"\"type\":"+ "\""+ type +"\""+
'}';
}
Your "temp fix" will store each object as a string not a object.
You need to serialize an object to get that data, not a list.
For example, using a Map
List<Card> cards = myDatabase.retrieveData();
Map<Map<String, Object>> fireMap = new TreeMap<>();
int i = 1;
for (Card c : cards) {
Map<String, Object> cardMap = new TreeMap<>();
cardMap.put("text", c.getText());
fireMap.put("id_" + (i++), cardMap);
}
Gson gson = new Gson();
String data = gson.toJson(fireMap);
i want to sort my data as par desc date in local cloudant query.
i have insert_ts in my database document.
my code for simple query is:-
public List<BasicDocumentMAP> allTasksWithAllArg(Map<String, Object> query, int skip, int limit, List<String> fields, List<Map<String, String>> sortDocument) {
int nDocs = this.sunDatastore.getDocumentCount();
QueryResult all = this.im.find(query, skip, limit, fields, sortDocument);
List<BasicDocumentMAP> arrayListBasicDocumentMAP = new ArrayList<>();
// Filter all documents down to those of type Task.
for (DocumentRevision rev : all) {
}}
please help me to sort data as date wise. thank you
Try this code:
Sql query :
Select _id , _rev , insert_ts , title from table
where year=2010 order by insert_ts
Cloudant query :
{
"selector": {
"year": {
"$gt": 2010
}
},
"fields": ["_id", "_rev", "insert_ts", "title"], //
"sort": [{"insert_ts": "asc"}]
}
Update: The original answer (at the bottom) shows you how to sort by year (OP asked how to get the year, so I assumed that was how they wanted to sort). This is how to sort by date:
Either change the insert_ts field to be a date, or add a new field that is a date, for example:
Date insertTsDate = null;
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy-hh-mm-ss-SS");
try {
insertTsDate = dateFormat.parse(insert_ts);
}
catch (Exception e) {
// handle exception
}
Then add a new field to your document called insert_ts_date (or whatever you want to call it), set it to the insertTsDate variable above, and sort like so:
List<Map<String, String>> sortDocument = new ArrayList<Map<String, String>>();
Map<String, String> sortByInsertTsDate = new HashMap<String, String>();
sortByInsertTsDate.put("insert_ts_date", "asc");
sortDocument.add(sortByInsertTsDate);
Original Answer:
I think you are going to have to explicitly add a year property to your document. If you have the year then just add it to your document. If you need to parse it from the string you can use regex or the Date/Calendar classes to parse the date:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy-hh-mm-ss-SS");
try {
Date date = dateFormat.parse(insert_ts);
Calendar c = Calendar.getInstance();
c.setTime(date);
int year = c.get(Calendar.YEAR);
}
catch (Exception e) {
// handle exception
}
Then issue your query as follows:
List<Map<String, String>> sortDocument = new ArrayList<Map<String, String>>();
Map<String, String> sortByYear = new HashMap<String, String>();
sortByYear.put("year", "asc");
sortDocument.add(sortByYear);
Hello i'm a newbie on firebase, i'm creating a simple app to store text data on my firebase database. My goal is just to store the text but it seems that i cannot store the text.
I have this code for my send button which gets the value from the textbox and send it to the database. I can't figure out what's wrong.
public void onSendButtonClick(View v) {
String message = mMessageEdit.getText().toString();
Map<String, String> values = new HashMap<>();
values.put("name", "puf");
values.put("message", message.toString());
mFirebaseRef.push().setValue(values);
mMessageEdit.setText("");
}
Hope you could help me with this simple newbie problem.
Thanks. :)
I usually make a long variable to save date in millisecond.
long currentTimeInMillis = System.currentTimeInMillis();
Map<String, String> values = new HashMap<>();
values.put("date", currentTimeInMillis);
mFirebaseRef.push().setValue(values);
And then to convert it back I use DateFormat class (from android.text.format)
public static String getDate(String dateFormat, long currentTimeInMillis) {
return DateFormat.format(dateFormat, currentTimeInMillis); }
// Example usage
getDate("dd/MM/yyyy hh:mm:ss", "38232213325");
Try using a Map of type Map<String, Object> to write your values:
public void onSendButtonClick(View v) {
String message = mMessageEdit.getText().toString();
Map<String, Object> values = new HashMap<>();
values.put("name", "puf");
values.put("message", message);
mFirebaseRef.push().setValue(values);
mMessageEdit.setText("");
}
I'm new to Firebase, and I've been really enjoying it so far. I'm running into a problem; I'm using the FirebaseListAdapter similar to the tutorial outline here: https://github.com/firebase/AndroidChat
To use the FirebaseListAdapter, I need to use data model objects (to get the automatic binding to work nicely). The problem is I also want to keep a timestamp value with that model object, and I want to get the timestamp from the Firebase server.
What I have currently that is NOT working is a class DataModelObject (similar to com.firebase.androidchat.Chat in the demo example) with a constructor like :
DataModelObject(String data1, String data2, Map enQTimeStamp)
which I then try to use like this:
DataModelObject dmo = new DataModelObject ("foo", "bar", ServerValue.TIMESTAMP);
myFirebaseRef.push().setValue(dmo);
This causes a JsonMappingException when I try to run that code. I found a code snippet here :
https://www.firebase.com/blog/2015-02-11-firebase-unique-identifiers.html
But it's worthwhile to note that on line 4 of the Android code example, that will cause a compile time error (as he is trying to put ServerValue.TIMESTAMP into a Map, and TIMESTAMP is a Map itself)
What is the right way to do this and maintain compatibility with FirebaseListAdapter?
This sounds similar to this question: When making a POJO in Firebase, can you use ServerValue.TIMESTAMP?
When creating POJOs used to store/retrieve data apart from the default empty constructor I usually use a constructor similar to this:
Param param1;
Param param2;
HashMap<String, Object> timestampCreated;
//required empty constructor
public DataObject(){}
public DataObject(Param param1, Param param2) {
this.param1 = param1;
this.param2 = param2;
HashMap<String, Object> timestampNow = new HashMap<>();
timestampNow.put("timestamp", ServerValue.TIMESTAMP);
this.timestampCreated = timestampNow;
}
Be sure to include a getter for the HashMap<> used to store the Timestamp:
public HashMap<String, Object> getTimestampCreated(){
return timestampCreated;
}
Then use the #Exclude annotation to create a getter that you can use in your code to get the value of the timestamp if you need it. The #Exclude annotation will cause Firebase to ignore this getter and not look for a corresponding property
#Exclude
public long getTimestampCreatedLong(){
return (long)timestampCreated.get("timestamp");
}
Here's how I do it
//member variable
Object createdTimestamp;
public YourConstructor(){
createdTimestamp = ServerValue.TIMESTAMP
}
#Exclude
public long getCreatedTimestampLong(){
return (long)createdTimestamp;
}
Your db object should include these:
public class FirebaseDbObject {
private final Object timestamp = ServerValue.TIMESTAMP;
//........
//........
Object getTimestamp() {
return timestamp;
}
#Exclude
public long timestamp() {
return (long) timestamp;
}
}
This will add an extra field called "timestamp" to your object.
Edit: The answer posted by MobileMon is not fully correct as it does not have getter method. This is the complete and correct answer.
Kotlin provides an easy way to achieve this by data classes. You can create it like
data class FirebaseRequestModel(
var start_time: Any = ServerValue.TIMESTAMP,
var stop_time: Long = 0,
var total_time: Long = 0,
)
and use it directly by
val firebaseModel = FirebaseRequestModel()
firebaseRef.setValue(firebaseModel)
This will get default values from data class.
Or even you can initiate your own values by
val firebaseModel = FirebaseRequestModel(ServerValue.TIMESTAMP, 2134, 0)
firebaseRef.setValue(firebaseModel)
Similar to Urgurcan's answer, but a bit cleaner so the caller doesn't have trouble guessing between getTimestamp vs timestamp.
public class FirebaseDbObject {
private Object timestamp = ServerValue.TIMESTAMP;
//........
//........
#PropertyName("timestamp")
Object getRawTimestamp() {
return timestamp;
}
#Exclude
public long getTimestamp() {
return (long) timestamp;
}
}
You can do it:
public class MyTimeStamp {
private Object timestamp;
public MyTimeStamp() {
}
public Object getTimestamp() {
return timestamp;
}
public void setTimestamp(Object timestamp) {
this.timestamp = timestamp;
}
}
And so:
public static void start(Context context) {
MyTimeStamp timeStamp = new MyTimeStamp();
timeStamp.setTimestamp(ServerValue.TIMESTAMP);
Log.d(TAG, "start: ", timeStamp.getTimestamp().toString());
}
I have been using GSON library to parse all the json string and get a JSON object.
But now I need to parse is like this:
{
"status":1,
"info":[
{
"\u5a31\u4e50":"\u51b7\u76d8,\u9ad8\u811a\u676f,\u6211\u7684\u7cd6\u679c\u5c4b,\u670d\u52a1\u4e1a\u6d88\u8d39\u52b5"
},
{
"\u7f8e\u5986":"\u4e2a\u62a4|\u5316\u5986#\u9762\u90e8\u62a4\u7406,\u4e2a\u4eba\u536b\u751f,\u8eab\u4f53\u62a4\u7406,\u9999\u6c34\u9999\u6c1b,\u6c90\u6d74|\u7f8e\u53d1\u7528\u54c1,\u5f69\u5986,\u7cbe\u6cb9SPA,\u773c\u90e8\u62a4\u7406,\u78e8\u7802\u53bb"
},
{
"\u8863\u670d":"\u670d|\u9970|\u978b|\u5e3d#\u670d\u88c5,\u978b\u9774,\u5185\u8863,\u914d\u9970,\u536b\u8863,\u4f11\u95f2\u88e4,T\u6064,\u88d9\u5b50,\u886c\u886b,\u9488\u7ec7\u886b,\u5a74\u5e7c\u513f\u670d\u9970"
}
],
"total":3
}
The key fields are dynamic, so I don't know how to write a model class to read this.
How would you like your model class to look?
status and total would probably be int, so that only leaves info.
As an experiment, just add a field Object info and see how Gson would set it to an ArrayList<LinkedHashMap<String, String>> -- ugly and hard to access by key, but all the data is there. Given that information, the fastest way to model a class would be:
class Something {
int status;
List<Map<String, String> info;
int total;
}
If you have control over how that JSON is generated, I suggest changing the structure of info from an array of objects [{a:b},{c:d},{e:f}] to just an object {a:b,c:d,e:f}. With this, you could just map it to a Map<String, String> with all the benefits like access by key, keys() and values():
class Something {
int status;
Map<String, String> info;
int total;
}
If you want the latter model class without changing the JSON format, you'll have to write a TypeAdapter (or JsonDeserializer if you're only interested in parsing JSON, not generating it from your model class).
Here's a JsonDeserializer hat would map your original info JSON property to a plain Map<String, String>.
class ArrayOfObjectsToMapDeserializer
implements JsonDeserializer<Map<String, String>> {
public Map<String, String> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
Map<String, String> result = new HashMap<String, String>();
JsonArray array = json.getAsJsonArray();
for (JsonElement element : array) {
JsonObject object = element.getAsJsonObject();
// This does not check if the objects only have one property, so JSON
// like [{a:b,c:d}{e:f}] will become a Map like {a:b,c:d,e:f} as well.
for (Entry<String, JsonElement> entry : object.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().getAsString();
result.put(key, value);
}
}
return result;
}
}
You need to register this custom JsonDeserializer similar to this:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(
new TypeToken<Map<String, String>>() {}.getType(),
new ArrayOfObjectsToMapDeserializer());
Gson gson = builder.create();
Note that this registers the custom deserializer for any Map<String, String> regardless in what class it is encountered. If you don't want this, you'll need to create a custom TypeAdapterFactory as well and check the declaring class before returning and instance of the deserializer.
Here goes a solution, which does not requires to make a JsonDeserializer.
All you can create is a JsonElement in a map Map.Entry<String, JsonElement>and use a for loop to iterate over the entries
//parsing string response to json object
JsonObject jsonObject = (JsonObject) new JsonParser().parse(jsonString);
//getting root object
JsonObject dateWiseContent = jsonObject.get("rootObject").getAsJsonObject();
for (Map.Entry<String, JsonElement> entry : dateWiseContent.entrySet()) {
//this gets the dynamic keys
String dateKey = entry.getKey();
//you can get any thing now json element,array,object according to json.
JsonArray jsonArrayDates = entry.getValue().getAsJsonArray();
}
read more here