Remove DataSnapshot From Firebase setValue() - android

My Firebase database storage format like this.
{
key=3553: 3223,
value={
-KZMFwmCYKevESD6qtjD={
text=Hello I am,
timestamp=[
.sv: timestamp
],
imageUrl=,
senderId=yDapbI755tOD72ivfsdferOv1RIHMnAe03
}
}
}
but at the time of set value to store in firebase database i am doing like this.
String Temp = "{timestamp: [.sv: timestamp], imageUrl: , senderId: " + Utils.SET_HEADER_ID + ", text: " + strMessage + "}";
System.out.println("===== Temp String : " + Temp);
String key = mFirebaseDatabaseReference.child("threads/3333:3333").push().getKey();
mFirebaseDatabaseReference.child("threads/3333:3333").child(key).setValue(Temp);
As I wrote above code I added a data in Firebase database. But it will automatically include DataSnapshot JsonObject at top my insert database format like this, which is wrong.
DataSnapshot{
key=3333: 3333,
value={
-KZPfTKJhaCC4RkIj45P={
timestamp: [
.sv: timestamp
],
imageUrl: ,
senderId: yDapbI755tOD72ivOv1RIHMnAe03,
text: hiiiiiiiii
}
}
}
How can I remove this DataSnapshot from insert format of Firebase?

You cannot pass a raw JSON value to Firebase. You'll instead have to build the data structure in your code:
Map<String,String> map = new HashMap<String,String>();
map.put("timestamp", Firebase.Database.ServerValue.TIMESTAMP);
map.put("imageUrl", "an actual image URL, which is missing from your question");
map.put("senderId", Utils.SET_HEADER_ID);
map.put("text", strMessage);
mFirebaseDatabaseReference.child("threads/3333:3333").child(key).setValue(map);
Alternatively you can use a library such as Jackson to convert the JSON intro the required nested map structure. See for example Nested Json to Map using Jackson.

Related

Display JsonArray from api and sort

I am trying to display data from a rest api containing a Json Array and a list of Json objects. I tried following a tutorial and was able to display the data on textview. What I actually want to do is gather the data in a Hashmap in terms of key and value pair and sort them accordingly.
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if(!response.isSuccessful()){
textView.setText("Code: " +response.code());
return;
}
int j=0;
List<Post> posts = response.body();
Map<Integer,String> data = new HashMap<Integer, String>();
// Iterating through post and saving data in content variable
for(Post post: posts)
{
String content ="";
//String name = post.getName();
if(!(post.getName()==(null)) && !(post.getName().equals("")))
{
data.put(post.getListid(),post.getName()); //For inserting data into hashmap
content += "ListID: " + post.getListid() + "" + "\n";
content += "Name: " + post.getName() + "" + "\n";
}
textView.append(content);
}
The current code saves the data in a content variable and displays it in the text view.
I am relatively new to using hashmap and retrofit for displaying data. I would really appreciate if someone could explain me where I am going wrong with my code. I tried printing out the data but was only able to print the last line and not the rest.
This is my Json file that I want to sort and display the data
[{"listId":2,"name":null},{"listId":2,"name":"Item 990"},{"listId":2,"name":null},{"listId":2,"name":null},{"listId":2,"name":""},{"listId":4,"name":"Item 771"},{"listId":2,"name":""}]
This is the code that I am using to displaying all my json data in textview
for(Map.Entry entry: data.entrySet())
{ textView.append(entry.getKey()+ " Value:" +entry.getValue() +"\n");}
I if understand correctly, you have a List<Post> posts that you want to sort out ? Why don't you sort the posts as you need and save them accordingly? You could just remove the post from your list if their name are null or ""

Build the data structure with relationship via Firebase

I am new in noSQL and Firebase. But I want to build the structure of my database via Firebase.
I have users and a list of users lots. Structure with relationship.
So I did what's in the example:
String key = mDatabase.child("lots").push().getKey();
//create new lot
Lot lot = new Lot(fbUser.getUid(), fbUser.getEmail(), mMessage.getText().toString());
//turn to map
Map<String, Object> lotValues = lot.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/lots/" + key, lotValues);
childUpdates.put("/user-lots/" + fbUser.getUid() + "/" + key, lotValues);
mDatabase.updateChildren(childUpdates);
But in the result I had this data to duplicate:
May be it's better to get this structure. I tried to find an example how to build one, because I do not want to to reinvent a wheel, but my efforts are futile so far.
Any suggestions? Thanks a lot.
What you're looking for is Pointers, which Firebase, believe it or not, DOES NOT have.
For example, if you want to have 3 lists of data:
My Posts
Recent Posts
Then you'll have to do it like this:
databaseRoot:{
Posts:{
{UNQ_KEY}:
{
title: "x",
description: "y",
authorUserID: {USERID1}
}
}
Users:{
{USERID1}
Posts:{
{UNQ_KEY_2}: {
title: "x",
description: "y"
}
}
}
}
When UNQ_KEY is created, you also create UNQ_KEY_2 under the user's userID.
To display "My Posts", you get the list under {USERID1}. To get "Recent Posts", you have to go to the Posts node.

Firebase , second push() in same method does not work

In my app , there is an activity which upon clicking the save button, 2 sets of data in 2 different places should be made by push(), Since in both places an unique id is needed.
I have followed the sample code in the Firebase guide and added the second push
String userId = auth.getCurrentUser().getUid().toString();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
DatabaseReference firstDatabaseRef = reference.child("first");
DatabaseReference secondDatabaseRef = reference.child("second").child(userId);
String key = firstDatabaseRef.child(userId).push().getKey();
First first = new First(firstAmount,key,firstName);
Map<String, Object> firstValues = first.toMap();
String keySecond = secondDatabaseRef.child(key).push().getKey();
Second second = new Second(secondName,secondAmount,keySecond,key);
Map<String, Object> secondValue = second.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/first/" + userId + "/" + key, firstValues);
childUpdates.put("/second/" + userId + "/" + key + "/" + keySecond, secondValue);
reference.updateChildren(childUpdates);
The result that i got for first was exactly as i expected but for second , instead of creating second/<userId>/<key>/<keySecond>/children, i get this :
"second" : {
//userId
"5TQLPlGf4mbcBRKesQwR30fH1L22" : {
//key
"-KL1030IywlNpkTGC7mU" : {
"secondAmount" : "147",
"Key" : "-KL1030IywlNpkTGC7mU",
"secondName" : "secondName",
"keySecond" : "-KL1030PZlHqD_asSR_8",
}
}
}
Instead of having the final children in another unique id, which by the way is recorded in the keySecond, they are all added directly to the key.
This cannot be accepted since every key must have many keySecond.
I hope that i explained my problem correctly.
Please tell me what am i doing wrong.
How should i modify my code or should i reconsider my data structure completely ?
This is a puzzle. I copy/pasted the code you posted and created stubs for First and Second. Running with Firebase 9.0.2 produced the result shown below, which I believe is what you are expecting. Are you running with a different Firebase version? Is it possible the JSON you posted was produced by a different version of the code you posted?
{
"first" : {
// userId
"ypx8RB3eglTBRPeUT7laQVQ1PZQ2" : {
// key
"-KL3rXeYrscFQNrVQnHb" : {
"firstAmount" : "FirstAmount",
"firstKey" : "-KL3rXeYrscFQNrVQnHb",
"firstName" : "FirstName"
}
}
},
"second" : {
// userId
"ypx8RB3eglTBRPeUT7laQVQ1PZQ2" : {
// key
"-KL3rXeYrscFQNrVQnHb" : {
// keySecond
"-KL3rXe_JyY9Vz2U-NES" : {
"Key" : "-KL3rXeYrscFQNrVQnHb",
"keySecond" : "-KL3rXe_JyY9Vz2U-NES",
"secondAmount" : "SecondAmount",
"secondName" : "SecondName"
}
}
}
}
}
When processing the updateChildren(), the Firebase Database loops over the children that you pass and for each key it essentially does a setValue() with the value you passed.
That means that if you have children with overlapping keys, the value of one of those keys will be written last. The order of these is undefined.
In your case it's fairly easy to merge the updates together:
String key = firstDatabaseRef.child(userId).push().getKey();
First first = new First(firstAmount,key,firstName);
Map<String, Object> firstValues = first.toMap();
String keySecond = secondDatabaseRef.child(key).push().getKey();
Second second = new Second(secondName,secondAmount,keySecond,key);
Map<String, Object> secondValue = trans.toMap();
firstValues.put(keySecond, secondValue); // This is the main change
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/first/" + userId + "/" + key, firstValues);
reference.updateChildren(childUpdates);

Sending and retrieving data from datastore with mobile backend starter

I'm trying to use Mobile Backend Starter in my Android application. In order to do that I need to store some data in the Datastore.
I'm using the provided object CloudEntity but I can only consistently insert and read String.
That's the example code I used to send data:
CloudEntity entity = new CloudEntity(TEST_KIND_NAME);
entity.put(KEY_DATE, new Date(System.currentTimeMillis()));
entity.put(KEY_CALENDAR, Calendar.getInstance());
entity.put(KEY_LONG, Long.valueOf(Long.MAX_VALUE));
entity.put(KEY_INTEGER, Integer.valueOf(Integer.MAX_VALUE));
getCloudBackend().insert(entity, simpleHandler);
and this is how I read the data back (next code goes in the onComplete in the CloudBackendHandler:
StringBuffer strBuff = new StringBuffer();
strBuff.append("Inserted: \n");
strBuff.append("\tId = " + result.getId() + "\n");
Object o;
o = result.get(KEY_DATE);
strBuff.append("\tDate was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_CALENDAR);
strBuff.append("\tCalendar was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_LONG);
strBuff.append("\tLong was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_INTEGER);
strBuff.append("\tInteger was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_BOOLEAN);
strBuff.append("\tBoolean was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
mTvInfo.setText(strBuff);
And what I get as result is:
Data inserted as Date and Calendar returns null.
Data inserted as Integer returns BigDecimal.
Data inserted as Longreturns a String.
My question is: Can I send (and read back) other data than `String? And if so. How?
After some time experimenting with the Android Mobile Backed Starter I found a link to a "sort of" (very limited) documentation: Mobile Backend Starter.
What I found is that if you send an Integer (and if I trust de documentation a Float or a Double) it is stored in the DataStore as a numeric field. And is returned as a BigDecimal when you send a query (through ClouldQuery).
Nevertheless, if you pass a Long as a property in your CloudEntity, it will be stored as a String in the DataStore and returned as such. And this is not trivial, as String fields has limitations on allowed comparisons.
If you send a DateTime, the documentation tells you that you will get back a String, but don't tells you that it will be stored in the DataStore as a String too.
This is important because you can't do all the comparisons with Strings. It is only allowed the equality (and ne) comparison (you can't test a greater than filter over a String property in your queries). So you can't store timestamps as Long (will be converted to String and you won't be able to compare them) and you can't set timestamps as DateTime for the same reason. And you just can't store Date nor Calendar objects.
Anyway every CloudEntity has two DateTime porperties by default CloudEntity.PROP_CREATED_AT and CloudEntity.PROP_UPDATED_AT. You can set a query filter with this fields. To do so you need to set the filter as
CloudQuery myQuery = new CloudQuery(<your kind name>);
myQuery.set<things>...
DateTime dateTime = new DateTime(<the time you want>);
myQuery.setFilter(F.gt(CloudEntity.PROP_UPDATED_AT, dateTime));
You need to use a DateTime for the comparison. If you are courious, you can NOT use Date instead of DateTime for this comparation. You would get this error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code": 400,
"errors": [
{
"domain": "global",
"message": "java.lang.IllegalArgumentException: _updatedAt:java.util.LinkedHashMap is not a supported property type.",
"reason": "badRequest"
}
],
"message": "java.lang.IllegalArgumentException: _updatedAt: java.util.LinkedHashMap is not a supported property type."
...
Other weird thing is that, aparently, you can not do comparisons with dateTime = new DateTime(0) (i.e. 1970-01-01T01:00:00.000+01:00) as the backend receives the query as:
query: (_kindName:"Data") AND ( _updatedAt > "1970-01-01T01:00:00.000+01:00" ), schema: {_kindName=STRING, _updatedAt=STRING}
Won't give any error but will return nothing list: result: null. Looks like it treats the comparison as a String. If you use DateTime dateTime = new DateTime(1) instead, you will send a query as:
list: executing query: {filterDto={operator=GT, values=[_updatedAt, 1970-01-01T01:00:00.001+01:00]},
looks the same as before but the backend will execute the query as:
query: (_kindName:"Data") AND ( _updatedAt > 1 ), schema: {_kindName=STRING, _updatedAt=DOUBLE}
As I see a DOUBLE I tried submit a Double instead a DateTime, but it doesn't work (no error but not result).
But, GOOD NEWS EVERYONE! We can do the comparison with an Integer as:
Integer anInteger = Integer.valueOf(0);
myQuery.setFilter(F.gt(CloudEntity.PROP_UPDATED_AT, anInteger));
the backend sees:
query: (_kindName:"Data") AND ( _updatedAt > 0 ), schema: {_kindName=STRING, _updatedAt=INT32}
and we'll get the expected value (all the entities updated since 1970-01-01T01:00:00.000+01:00)
Sorry for my mistakes (my english isn't good) and I hope this can help someone and, at least, save him some time.

get array of KEYS for each element under jsonarray

I want to parse my Json array dynamically. and want to get array of KEYS for each element under jsonarray. i an getting this through iterator. but not getting the sequeance as per the output json formate.
my JSON Formate :
{
"result": "Success",
"AlertDetails": [
{
"ShipmentNumber": "SHP34",
"Customer": "BEST",
"DateCreated": "2012-08-29T04:59:18Z"
"CustomerName": "BEST"
},
{
"ShipmentNumber": "SHP22",
"Customer": "BEST",
"DateCreated": "2012-08-29T05:34:18Z"
"CustomerName": "Jelly"
}
]
}
here is My Code :
JSONArray array = jsonobject.getJSONArray("AlertDetails");
JSONObject keyarray = array.getJSONObject(0);
Iterator temp = keyarray.keys();
while (temp.hasNext()) {
String curentkey = (String) temp.next();
KEYS.add(curentkey);
}
Log.d("Parsing Json class", " ---- KEYS---- " + KEYS);
What i am getting in logcate output:
---- KEYS---- [DateCreated,CustomerName, Customer, ShipmentNumber]
What i want :
---- KEYS---- [ShipmentNumber, Customer, DateCreated,CustomerName]
The JSONObject documentation (link: http://developer.android.com/reference/org/json/JSONObject.html) has the following description for the keys() function:
public Iterator keys ()
Since: API Level 1
Returns an iterator of the String names in this object. The returned
iterator supports remove, which will remove the corresponding mapping
from this object. If this object is modified after the iterator is
returned, the iterator's behavior is undefined. The order of the keys
is undefined.
So you may get the keys but the order is undefined. You may use any of the sorting algorithms if you want the keys in any particular order.
EDIT
Since you are unaware of the order of KEYS you are getting from the WS, after receiving the data you may show the details on screen in an ordered format . After building the arraylist KEYS, you may sort it alphabetically using the following:
Collections.sort(KEYS);
This will order the Strings in the KEYS arraylist according to its natural ordering (which is alphabetically).
I just come to know when I press ctlr+space bar, in which its clearly written that behavior of the keys is undefined, orders is not maintain by keys.
Arun George said# correctly that you have to use any sorting method to achieve your goal.
and for sorting may be this link will help you.
Use GSON library from google. It has a a lot of setting to read/create/parse json array and json objects. I didn't test it to find the solution, but I think it's very simple and full featured tool and can solve the problem.
Use different library to parse json dynamically.
Below I wrote a piece of code based on Jackson JSON Processor, which is the best JSON library in my opinion
public void test() throws IOException {
String str = "{\n" +
" \"result\": \"Success\",\n" +
" \"AlertDetails\": [\n" +
" {\n" +
" \"ShipmentNumber\": \"SHP34\",\n" +
" \"Customer\": \"BEST\",\n" +
" \"DateCreated\": \"2012-08-29T04:59:18Z\",\n" +
" \"CustomerName\": \"BEST\"\n" +
" }\n" +
" ]\n" +
"}";
JsonFactory factory = new JsonFactory();
JsonParser jsonParser = factory.createJsonParser(str);
JsonToken jsonToken;
SerializedString alertDetails = new SerializedString("AlertDetails");
while (!jsonParser.nextFieldName(alertDetails)) { /* move to AlertDetails field */ }
jsonParser.nextToken(); // skip [ start array
jsonParser.nextToken(); // skip { start object
// until } end object
while ((jsonToken = jsonParser.nextToken()) != JsonToken.END_OBJECT) {
if (jsonToken == JsonToken.FIELD_NAME) {
System.out.println(jsonParser.getCurrentName());
}
}
}
It simply prints out field names in the same order as in json:
ShipmentNumber
Customer
DateCreated
CustomerName
EDIT
Naturally you can use other libraries like gson etc. But remember, as is written on json.org, that:
An object is an unordered set of name/value pairs.
and the order of keys depends on implementation and might vary in each request.
There is also the method names();
Returns an array containing the string names in this object.
Edit: returns names in undefined order. Suggestions: parse it on your own

Categories

Resources