Firebase snapShot value order changed after converting to NSDictionary - ios

I am trying to get data from firebase database using firebase query
self.getReferencePath().child(User.followingReferencePath).queryOrderedByKey().queryLimited(toLast: 5)
When I pass this query to firebase and print the snapshot.value, I get the data in the order present in firebase as following
snapshot.value {
"-L2_hNtqB5UCBzgMFX0m" = {
"debate_id" = "-L2_hNtqB5UCBzgMFX0m";
};
"-L2_hSQSl7T5cDCfDoiV" = {
"debate_id" = "-L2_hSQSl7T5cDCfDoiV";
};
"-L2_h_vrwqID5Esl6gOk" = {
"debate_id" = "-L2_h_vrwqID5Esl6gOk";
};
"-L2_hfAruruMjzrLEZtI" = {
"debate_id" = "-L2_hfAruruMjzrLEZtI";
};
"-L2_hk2Uq7IBcflkO5YQ" = {
"debate_id" = "-L2_hk2Uq7IBcflkO5YQ";
};
}
But after converting the snapshot.all values as NSArray, the order changes as follow
let followingDbate = followingDebatesSnapshot.allValues as NSArray
print("followingDbate",followingDbate)
followingDbate (
{
"debate_id" = "-L2_hk2Uq7IBcflkO5YQ";
},
{
"debate_id" = "-L2_h_vrwqID5Esl6gOk";
},
{
"debate_id" = "-L2_hfAruruMjzrLEZtI";
},
{
"debate_id" = "-L2_hNtqB5UCBzgMFX0m";
},
{
"debate_id" = "-L2_hSQSl7T5cDCfDoiV";
}
)
I want to get the last Id as=nd pass it through another query. As the order changes I am not able to get the last id correctly. Please advice how to get the data without changing the order and also ow to get the last id from the snapshot I get. Thanks in advance

Related

Firebase -how to run a calculation using a Cloud Function

I have a food app with a star system. Every time a user selects a rating/star I send their rating to the database and then run a firebase transaction to update the total amount of users who left a rating.
let theirRating: Double = // whatEverStarRatingTheySelected
let dict = [currentUserId: theirRating]
let reviewsRef = Database.database().reference().child("reviews").child(postId)
reviewsRef.updateChildValues(dict) { (error, ref) in
let postsRef = Database.database().reference().child("posts").child(postId).child("totalUsersCount")
postsRef.runTransactionBlock({ (mutableData: MutableData) -> TransactionResult in
// ...
})
}
When displaying the actual rating I pull the the post which has the totalUsersCount as a property, I pull all of the users actual ratings, add them all together, and then feed both numbers into an algo to spit out the actual rating. I do all of this on the client. How can I do the same thing "I pull all of the users actual rating, add them all together" with a Cloud Function, that is similar to this answer?
Database.database().reference().child("posts").child(postId).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dict = snapshot.value as? [String:Any] else { return }
let post = Post(dict: dict)
let totalUsers = post.totalUsersCount
Database.database().reference().child("reviews").child(postId).observeSingleEvent(of: .value, with: { (snapshot) in
var ratingSum = 0.0
// *** how can I do this part using a Cloud Function so that way I can just read this number as a property on the post instead of doing all of this on the client ***
for review in (snapshot.children.allObjects as! [DataSnapshot]) {
guard let rating = review.value as? Double else { continue }
ratingSum += rating
}
let starRatingToDisplay = self.algoToComputeStarRating(totalUsersCount: totalUsersCount, ratingsSum: ratingSum)
})
})
This isn't a question about the algoToComputeStarRating, that I can do on the client. I want to add all of the user's ratings together using a Cloud Function, then just add that result as a property to the post. That way when I pull the post all I have to do is:
Database.database().reference().child("posts").child(postId).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dict = snapshot.value as? [String:Any] else { return }
let post = Post(dict: dict)
let totalUsersCount = post.totalUsersCount
let ratingsSum = post.ratingsSum
let starRatingToDisplay = self.algoToComputeStarRating(totalUsersCount: totalUsersCount, ratingsSum: ratingSum)
})
Database structure:
#posts
#postId
-postId: "..."
-userId: "..."
-totalUsersCount: 22
-ratingsSum: 75 // this should be the result from the cloud function
#reviews
#postId
-uid_1: theirRating
-uid_2: theirRating
// ...
-uid_22: theirRating
This is what I tried so far:
exports.calculateTotalRating = functions.https.onRequest((data, response) => {
const postId = data.postId;
const totalUsersCtRef = admin.database().ref('/posts/' + postId + '/' + 'totalUsersCt');
const postsRef = admin.database().ref('/posts/' + postId);
admin.database().ref('reviews').child(postId).once('value', snapshot => {
if (snapshot.exists()) {
var ratingsSum = 0.0;
snapshot.forEach(function(child) {
ratingsSum += child().val()
})
.then(() => {
return postsRef.set({ "ratingsSum": ratingsSum})
})
.then(() => {
return totalUsersCtRef.set(admin.database.ServerValue.increment(1));
})
.catch((error) => {
console.log('ERROR - calculateTotalRating() Failed: ', error);
});
}
});
});
I got it to work using this answer:
exports.calculateTotalRating = functions.https.onRequest((data, response) => {
const postId = data.postId;
const postsRef = admin.database().ref('/posts/' + postId);
const totalUsersCtRef = admin.database().ref('/posts/' + postId + '/' + 'totalUsersCt');
var ratingsSum = 0.0;
admin.database().ref('reviews').child(postId).once('value', snapshot => {
if (snapshot.exists()) {
snapshot.forEach((child) => {
ratingsSum += child().val()
})
console.log('ratingsSum: ', ratingsSum);
return postsRef.update({ "ratingsSum": ratingsSum }).then(() => {
return totalUsersCtRef.set(admin.database.ServerValue.increment(1));
})
.catch((error) => {
console.log('ERROR - calculateTotalRating() Failed: ', error);
});
}
});
});
I think this should provide you a good start. I have used a trigger so all the updates will happen automatically and your swift listener will immediately get the new ratings. :) Though I am not sure how your let post = Post(dict: dict) is going to parse the [String: Any] dictionary.
//We are adding a event listner that will be triggered when any child under the reviews key is modified. Since the key for updated review can be anything we use wildcards `{autoId}`.
exports.calculateTotalRating = functions.database
.ref("reviews/{autoId}")
.onUpdate((snapshot, context) => {
if (snapshot.exists()) { //For safety check that the snapshot has a value
const ratingsDict = snapshot.val(); //The updated reviews object you set using `reviewsRef.updateChildValues(dict)`
const autoId = context.params.autoId; //Getting the wildcard postId so we can use it later
//Added due to error in understanding the structure of review object. Can be ignored.
//delete ratingsDict("totalUserCount");
//delete ratingsDict("ratingsSum");
const totalUsers = Object.keys(ratingsDict).length; //Counting how many reviews are there in the ratingsDict
//Sum over all the values in ratingsDict. This approach is supposedly slower, but was oneliner so used it. Feel free to modify this with a more efficient way to sum values once you are more comfortable with cloud functions.
const ratingsSum = Object.keys(ratingsDict).reduce(
(sum, key) => sum + parseFloat(ratingsDict[key] || 0),
0
);
//Saving the computed properties.
ratingsDict["totalUserCount"] = totalUsers;
ratingsDict["ratingsSum"] = ratingsSum;
//Updating posts with new reviews and calculated properties
return functions.database.ref("posts").child(autoId).set(ratingsDict);
}
});
I feel like you are new to this, so you can follow this guide to create cloud functions. In your app's top level directory, just run firebase init functions and selecting your project from Use an existing project. This should create a functions folder for you with an index.js file where you can add this code. Then just run firebase deploy --only functions:calculateTotalRating.

how to extract Elements in NSMutable Dictionary Array

my server sends me an response in hierarchy way i do no how to grab the value from that
here my sample response :
{
id = "-1";
result = (
{
keyname = "Warranty Expiry Date";
value = "06-14-2017";
}
);
},
{
id = "-1";
result = (
{
keyname = Owner;
value = "";
}
);
},
{
id = "-1";
result = (
{
keyname = Model;
value = "";
}
);
},
{
id = "-1";
result = (
{
keyname = "Price $";
value = 1000;
}
);
},
{
id = "-1";
result = (
{
keyname = Vendor;
value = "";
}
);
},
{
id = "-1";
result = (
{
keyname = "Purchase Date";
value = "";
}
);
}
)
here is sample Java code how they extracted the values
Hashtable htAttrs = (Hashtable) editedAttrHash.get(assItmId);
if (htAttrs != null) {
Set<String> keys = htAttrs.keySet();
for (String deAttr : keys) {
xmlSerializer.startTag("", "attribute");
xmlSerializer.attribute("", "keyname", deAttr);
xmlSerializer.attribute("", "value",
htAttrs.get(deAttr).toString());
xmlSerializer.endTag("", "attribute");
}
}
i need to do no how to from this structure past one day i am blocked here anyone can fix my problem
How to extract values from nsmutablearray?If it is really nsmutablearray object, then extract the values is simple.
For example, to get id of first element:
NSString firstId = response[0][#"id"]
But it seems, like for now, it is just a json object. So, you should serialize it to nsarray object first.

How to access NSArray inside a NSDictionary while parsing a xml?

I am using XMLReader to parse a xml response. I have converted the xml to a NSDictionary. Now i want to access the array named 'cTrx' inside the NSDictionary. This is my NSDictionary:
{
Envelope = {
Body = {
fRetrieveTransactionsforReversalResponse = {
fRetrieveTransactionsforReversalResult = {
pCellularNumber = {
text = 0825669995;
};
pResponseCode = {
text = 00;
};
pResponseMessage = {
text = Approved;
};
pTrx = {
cTrx = (
{
pCardHolderName = {
};
pReference = {
text = 140826121114;
};
pTransactionAccount = {
text = "364241****0016";
};
pTransactionDate = {
text = "8/26/2014 12:11:18 PM";
};
pTransactionID = {
text = 23;
};
},
{
"xsi:nil" = true;
}
);
};
};
};
};
};
}
Thanks.
You can access dictionary and array values with square brackets:
val = dictionary[#"key"];
item = array[i];
It works for nested dictionaries as well:
NSDictionary *nested = #{#"dict_key": dictionary};
dictionaryVal = nexted[#"dict_key"][#"key"];
So, in your case, you could access cTrx array in next way:
NSArray *cTrx = yourDictionary[#"Envelope"][#"Body"][#"fRetrieveTransactionsforReversalResponse"][#"pTrx"][#"cTrx"];
Long string of code :)

How to write ItemQuery using ListIdSet?

I have requirement to retrive Item information for multiple Ids, I am using ItemQuery for the same using below code,but its gives error as "{"Invalid or missing value of the choice identifier 'ItemsElementName' of type 'Intuit.Ipp.Data.Qbd.ItemsChoiceType4[]'."}".
Please suggest if anyone is having any idea about how to use ListIdSet for ItemQuery .
List<Intuit.Ipp.Data.Qbd.IdType> ids = new List<Intuit.Ipp.Data.Qbd.IdType>();
ids.Add(new Intuit.Ipp.Data.Qbd.IdType() { Value = "123460", idDomain = Intuit.Ipp.Data.Qbd.idDomainEnum.NG });
ids.Add(new Intuit.Ipp.Data.Qbd.IdType() { Value = "789100", idDomain = Intuit.Ipp.Data.Qbd.idDomainEnum.NG });
ids.Add(new Intuit.Ipp.Data.Qbd.IdType() { Value = "111213", idDomain = Intuit.Ipp.Data.Qbd.idDomainEnum.NG });
Intuit.Ipp.Data.Qbd.ItemQuery qbdQuery = new Intuit.Ipp.Data.Qbd.ItemQuery();
List<Intuit.Ipp.Data.Qbd.Item> itemQueryResult = null;
qbdQuery.Items = ids.ToArray();
qbdQuery.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.ListIdSet};
itemQueryResult = qbdQuery.ExecuteQuery<Intuit.Ipp.Data.Qbd.Item>(context).ToList<Intuit.Ipp.Data.Qbd.Item>();
Regards,
Reshma D.
Here is an example
ItemQuery qbdItemQuery = new ItemQuery();
qbdItemQuery.Items = new object[] { new IdSet() { Id = new IdType[] { new IdType() { idDomain = idDomainEnum.NG, Value = "79841" } } } };
qbdItemQuery.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.ListIdSet };
List<Item> ItemQueryResult = qbdItemQuery.ExecuteQuery<Item>(context).ToList<Item>();

iOS5 - How to parse JSON response from Facebook [duplicate]

I am using Facebook Graph API...for fetching the data of news feed of the facebook profile..
and here is the response that i am getting in the console
{
application = {
id = 2309869772;
name = Links;
};
"created_time" = "2011-02-10T09:44:27+0000";
from = {
id = 1845195019;
name = "Paritosh Raval";
};
icon = "http://static.ak.fbcdn.net/rsrc.php/v1/yD/r/aS8ecmYRys0.gif";
id = "1845195019_192144087475935";
likes = {
count = 1;
data = (
{
id = 1845195019;
name = "Paritosh Raval";
}
);
};
link = "http://www.facebook.com/AMDAVAD";
name = "once you live in AHMEDABAD u cannot live anywhere else in the world..";
picture = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/203562_115963658443669_4129246_n.jpg";
properties = (
{
name = Page;
text = "21,803 people like this.";
}
);
type = link;
"updated_time" = "2011-02-10T09:44:27+0000";
},
{
application = {
id = 2392950137;
name = Video;
};
"created_time" = "2011-02-02T04:18:22+0000";
description = "must watch and explore :))";
from = {
id = 1845195019;
name = "Paritosh Raval";
};
icon = "http://static.ak.fbcdn.net/rsrc.php/v1/yD/r/aS8ecmYRys0.gif";
id = "1845195019_194836027209359";
likes = {
count = 1;
data = (
{
id = 100000701228096;
name = "Bhargav Jani";
}
);
};
link = "http://www.facebook.com/video/video.php?v=152586058110610&comments";
name = "It Happens Only in....";
"object_id" = 152586058110610;
picture = "http://vthumb.ak.fbcdn.net/hvthumb-ak-snc4/50893_152586468110569_152586058110610_18299_1832_t.jpg";
properties = (
{
name = Length;
text = "0:54";
}
);
source = "http://video.ak.fbcdn.net/cfs-ak-ash2/70137/56/152586058110610_53804.mp4?oh=481e53b824f6db8e3195fc9c0d07571d&oe=4DAFC300&__gda__=1303364352_7670272db65e93ec75dcaaed16b6d805";
type = video;
"updated_time" = "2011-02-02T04:18:22+0000";
}
And I want to show every data in the organized structure in the console. Can anyone help me with this?
it's unclear what you exactly asking but I try to answer.
First of all you need to parse this response in the method
- (void)request:(FBRequest *)request didLoad:(id)result of Facebook iOS SDK
result can be a string, a NSArray if you have multiple results and NSDictionary
In you console output we can see NSDictionary with included arrays and dictionaries in it.
I have little tutorial about it but it's on russian only and site is down today :( so i just copy one example from my article.
Let say we want to know what facebook user Likes
- (IBAction)getUserInfo:(id)sender {
[_facebook requestWithGraphPath:#"me/likes" andDelegate:self];
}
if we try this Graph API response in browser or output to console we can see what this request returns. It returns dictionary with one and only key - "data" and corresponded array to this key. This array contents dictionary objects again with keys -
«name»,"category","id","created_time". Dont forget request «user_likes» permission before.
So we have parsing method like that:
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]]) {
result = [result objectAtIndex:0];
}
if ([result objectForKey:#"owner"]) {
[self.label setText:#"Photo upload Success"];
} else if ([result objectForKey:#"data"]){
NSArray *likes = [result objectForKey:#"data"];
NSString *text=#"You don't like Steve";
for (NSDictionary* mylike in likes) {
NSString *mylikeName = [mylike objectForKey:#"name"];
if ([mylikeName isEqualToString:#"Steve Jobs"]) {
text=#"You like Steve";
break;
}
}
[self.label setText:text];
}
};
You can parse you result same way and fill your object's variables and then use it to display information in TableView for example. good luck!

Resources