How to get chronologically latest post from Firebase? - ios

I am working on app in which Facebook like news feed is used,and i am using Firebase as a database. Everything is working fine, I just need to fetch posts, time wise.
FIRDatabaseQuery * query = [[[_firebaseReference child:#"Demo"]child:#"posts"]queryLimitedToFirst:100];
[query observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
if (snapshot.exists) {
postsDictionary = snapshot.value;
[self createSocialAppDataSource];
}
}];
The data in postsDictionary is same as in Database,But i want that data (post) to get sorted respect to time,So how to use query?
structure of my post in database as follow
Thanks

To filter the nodes on a child property, call queryOrderedByChild.
Then when you execute the query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
So you'll need to loop over the children:
FIRDatabaseQuery * query = [[[[_firebaseReference child:#"Demo"] child:#"posts"] queryOrderedByChild: "dateTime"] queryLimitedToFirst:100];
[query observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
for ( FDataSnapshot *child in snapshot.children) {
NSLog(#"child.key = %#",child.key);
}
}];
Loosely based on my answer here: IOS Firebase: Loop all key in snapshot.value get messy position

Usually people append the array they are feeding into the collectionView or tableView (for example) but in your case you can [myMutableArray insertObject:myObject atIndex:0]; now when you enumerate through your snapshot each post will be added to the front of your array

Related

how to get the unique key that was created adding a child in firebase?

I am using firebase database for my ios project.
I added some fields using childByAutoId.
[[[_ref child:#"Users"] childByAutoId] setValue:#{#"data": #"my new json data string By aqeel", #"email": #"abc.xyz#email.com"}];
Now for some reason I have to search a specific child from database, say an email id. If email id exists I want to get that unique key of that child.
I am doing this
[[[[_ref child:#"Users"] queryOrderedByChild: #"email" ] queryEqualToValue:#"abc.xyz#email.com" ] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSLog(#"%# Key %# Value", snapshot.key,snapshot.value);
}];
Here in key I get "Users" and in value I get all the entries inUsers field. But I want to get the key for the child abc.xyz#email.com.
Can someone provide me a sample code?
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
This means that you will have to loop over the snapshot.children.
Alternatively you can listen for a single .ChildAdded event and get the child that way:
[[[[_ref child:#"Users"]
queryOrderedByChild: #"email" ]
queryEqualToValue:#"abc.xyz#email.com" ]
observeSingleEventOfType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
NSLog(#"%# Key %# Value", snapshot.key,snapshot.value);
}];

Pagination With Dynamic Content

I'm trying to figure out the proper way to paginate results using the Parse SDK for iOS. The problem I'm having is that the content I'm trying to paginate has the potential to change frequently.
For example:
There is an app with a bunch of objects stored on a server, and the request to get these objects is sorted with newest first and paginated in case there are a lot of objects. When the user scrolls, as they are approaching the last object on the current page, the next page gets requested.
Say the user scrolls to page two, then a new object is added to the list of objects, and the user then scrolls up another page. When the next page is requested, they will get a duplicate of the last message on the second page, and since page 0 has already been loaded, the new object won't be displayed.
How can something like this be handled?
How would the implementation change if the objects were sorted oldest first?
Thanks in advance for the help.
Edit: request pseudo code
- (void)fetchObjectsForPage:(NSUInteger)page completion:(void (^)(NSArray *_Nullable objects, PageInfo *_Nullable pageInfo, NSError *_Nullable error))completion{
PFQuery *query = [SomeObject query];
[query orderByAscending:#"updatedAt"];
[query setLimit:50];
[query setSkip:50 * page];
[query findObjectsInBackgroundWithBlock:^{NSArray *_Nullable objects, NSError *_Nullable error){
...
>>> Do error checking and return array along with paging info (total number of objects, page size) or error in completion block.
}];
}
It's not the request I'm having trouble with, it's figuring out how to properly handle paging in the table when a new object gets added.
What you can do is the following:
Create a query that will return 50 rows (like you did) order by updatedAt
When you get result take the last item from the list and save the item updatedAt in some global property
In the next call do not use setOffset but get the next 50 rows and add another condition of where updatedAt is greater than the updatedAt of your global object. This way you make sure that you will not have duplicate records in your list
At the end your code should look like the following:
PFQuery *query = [PFQuery queryWithClassName:#"SomeClassName"];
[query orderByAscending:#"updatedAt"];
[query setLimit:50];
if (self.lastItemUpdatedAt){
[query whereKey:#"updatedAt" greaterThan:self.lastItemUpdatedAt];
}
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (objects.count > 0){
self.lastItemUpdatedAt = [[objects lastObject] updatedAt];
}
}];
Now if you use updatedAt there is a chance that you will still get duplicates because let's assume that someone change the object so the updatedAt will also be changed (so it will be greater than the updatedAt that you saved) in this case you can use createdAt instead of updatedAt since createdAt will never be changed

How to retrieve an specific child in Firebase?

The childByAutoId would be useful if you want to save in a node multiple children of the same type, that way each children will have its own unique identifier.
pet:{
KJHBJJHB:{
name:fluffy,
owner:John Smith,
},
KhBHJBJjJ:{
name:fluffy,
owner:Jane Foster,
}
}
Therefore, once I have that uID, and I want to retrieve an specific user using the his/her uID. How do I tell Firebase that I want that specific user? Because I create it and store it in Firebase, but then to read it, don't I need to know the value of the uID? Where do I get it from?
What function do I use to retrieve for example the second user using the uID?
Thanks in advance..
in the title u ask how to get rid so:: get the new ref's key property to get the aid created
FIRDatabaseReference *ref = parent.childByAutoID
NSString *uid = ref.key
BUT thats not what you want id say, so:
to filter out all children where owner = XY which you want I think:
FIRDatabaseReference *ref = your pets node
FIRDatabaseQuery *allPets = [ref queryOrderedByChild:#"owner"];
FIRDatabaseQuery *specificPet = [allPets queryEqualToValue:#"XY"];
[specificPet observeEventType:FEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
NSDictionary *dict = snapshot.value;
NSString *key = snapshot.key;
NSLog(#"key = %# for child %#", key, dict);
}];
see: Query users by name or email address using Firebase (Swift)

Firebase iOS query not ordering as expected

I have saved my data using childByAutoId so that it is ordered chronologically in Firebase. When I query using the query below, and then I print the snapshot.value it prints in the orders as I expected --ordered chronologically--, but when I try to enumerate over snapshot.value, and when I try to get the keys with [snap.value allkeys], they are no longer ordered chronologically. I have tried using [self.refMyOrder queryOrderedByKey] and [self.refMyOrders queryOrderedByChild:#"timestamp" for which I have a child timestamp that is a data-type long of the Epoch time. But still, it is not maintaining the desired order.
I understand that the underlying data structure of an NSDictionary is not an ordered data structure.
What am I doing wrong?
[self.refMyOrders observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
NSLog(#"snapshot.value = %#", snapshot.value);
NSLog(#"all keys = %#", [snapshot.value allKeys]);
}];
So, I read the FDataSnapshot.h header file that comes with the Firebase iOS SDK, and found a way to enumerate over the snapshot so that it remains in the proper order.
[self.refMyOrders observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
for (FDataSnapshot* child in snapshot.children) {
NSLog(#"%# -> %#", child.value[#"orderID"], child.value[#"timestamp"]);
}
}];
This is exactly what I was looking for. I will leave this question here for future users. I couldn't find anything this simple.

Retrieve SAVED objectID from Parse

Im trying to retrieve the objectId of my parse records. I can save and retrieve data ok, but having gone through all parse documents, Google, and SO, I can't seem to get a clear answer on how to get the id for accessing records before the main block without hard coding the objectId as in the tutorial from Parse.
getObjectInBackgroundWithId:#"SS8Cw7rT1h" <-------- Trying to retrieve object id to go here
Im saving data to parse inc objectId here (all good)
PFObject *scheme = [PFObject objectWithClassName:#"SchemeProvider"];
//Sections of class
scheme[#"schemeName"] = self.schemeName.text;
scheme[#"schemeRegistrationNumber"] = self.registrationNumber.text;
//Save then get object id of saved row
[scheme saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[scheme objectId];
NSLog(#"SCHEME ROW ID %#",[scheme objectId]);
}];
Retrieving from parse (all good) - except - can't get objectID before main block
PFQuery *queryScheme = [PFQuery queryWithClassName:#"SchemeProvider"];
//NSString *myobjectId = [queryScheme valueForKey:#"objectId"]; <------trying to retrive object id
[queryScheme getObjectInBackgroundWithId:#"SS8Cw7rT1h" block:^(PFObject *retrivedData, NSError *error) {
NSLog(#"All data = %#", retrivedData);
}];
I have just hit this problem and have an example for you in swift
There is a function that saves with a block in background
You can access the objectId while saving in the block thats run after saving it to the cloud
var foo = PFObject(className:"Foo")
foo["bar"] = "something"
foo.saveInBackgroundWithBlock(){(succeeded: Bool!, error:NSError!) in
if succeeded
{
self.fooLabel.text = foo.objectId
}
}
You could store the objectId for a certain object e.g in a data structure or with core data if you need it for later access
Otherwise you need to query the object with property values i guess
like seen here: https://www.parse.com/docs/ios_guide#queries-basic/iOS
Hope this helps

Resources