swift parse query how to get first createdAt for each username? - swift

How can i get First rows of createdAt for each username?
for example: backend looks like this
objectId- username - photo - createdAt
5135Aer - name1 - image - 2015-08-21
R35AAA - name6 - image - 2015-08-21
G7356W - name3 - image - 2015-08-20
E355B - name1 - image - 2015-08-20
So i want the query will take all rows and skip name1 which is createdAt 2015-08-20 last one because this old row i just want new createdAt rows only for each user.
let query = PFQuery(className: "test")
query.whereKey("receivers", equalTo: PFUser.currentUser()!.username!)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if error == nil {
self.createdAtArray = objects!
print(objects!.count)
I've tried this query but it will take old createdAt and i just want new createdAt for each user , And yes i have set limit to = 1 , but it will show last record not for each user! It just show one result.

So each 20 minutes from now I ask to give the recent object, so if you want query images after 50 minutes or more just change the value for timestamp.
let query = PFQuery(className: "test")
query.whereKey("receivers", equalTo: PFUser.currentUser()!.username!)
query.orderByDescending("createdAt")
var timeStamp = NSDate(timeIntervalSinceNow: -1200)
query.whereKey("createdAt", greaterThanOrEqualTo: timeStamp)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objects = objects as? [PFObject]
{
for one in objects
{
var Getimage = one["image"] as! PFFile
Getimage.getDataInBackgroundWithBlock({ (data:NSData?, error:NSError?) -> Void in
var image = UIImage(data: data!)
// you have the image now
createdAtArray.addObject(image!)
})
}
}
}
}
Second Option : To get the last object from parse use **getFirstObject method
func secondQuery(arraydetails:NSMutableArray){
var query = PFQuery(className: "")
query.orderByDescending("createdAt")
query.limit = 1
query.getFirstObjectInBackgroundWithBlock { (object:PFObject?, error:NSError?) -> Void in
if error == nil
{
var detail = object?.objectForKey("text") as! String
arraydetails.addObject(detail)
}
}
}

Related

Swift sort of array always in ascending order

i try to show a array list sorted by its Timestamp in an descending order (newest first --> highest ts first) therefore i created a downloading method and a sorting method:
func getBlogsByAuthor(){
self.allBlogs.removeAll()
for authorId in self.authorIds{
db.collection("Blogs").whereField("authorId", isEqualTo: authorId)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
let ts = document.get("ts") as! Int
let title = document.get("title") as! String
let body = document.get("body") as! String
let authorId = document.get("authorId") as! String
let state = document.get("stateios") as? String
let imageUrl = document.get("imageUrl") as! String
let id = document.documentID as! String
let blogObject = BlogObject.init(title: title , body: body, imageUrl: imageUrl , authorId: authorId , state: state ?? "Null" , id: id, ts: ts )
self.allBlogs.append(blogObject)
}
self.sortDataset()
}
}
}
}
func sortDataset(){
self.allBlogs.sorted(by: { $0.ts! < $1.ts! })
self.rv.reloadData()
}
The problem is that the values are showing always the lowest ts first no matter if i change it from self.allBlogs.sorted(by: { $0.ts! < $1.ts! })
to self.allBlogs.sorted(by: { $0.ts! > $1.ts! })
You need
self.allBlogs.sort { $0.ts! < $1.ts! } // mutating sort in place
as sorted(by returns a result that you ignore it and don't re-assign it would be
self.allBlogs = self.allBlogs.sorted(by: { $0.ts! < $1.ts! })

Paginate posts to collection view with firebase & swift

I'm trying to paginate posts that users are following to my collection view from my firebase database. Currently only 4 posts are being appended to the collection view and not loading anymore when I scroll down.
I've tried changing the number of posts loaded initially with no luck.
fileprivate func fetchFollowingUserIds() {
guard let uid = Auth.auth().currentUser?.uid else { return }
Database.database().reference().child("user-following").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
Database.fetchUserWithUID(uid: key, completion: { (user) in
self.fetchPostsWithUser(user: user)
})
})
}) { (err) in
print("Failed to fetch following user ids:", err)
}
}
var posts = [Post]()
fileprivate func fetchPosts() {
guard let uid = Auth.auth().currentUser?.uid else { return }
Database.fetchUserWithUID(uid: uid) { (user) in
self.fetchPostsWithUser(user: user)
}
}
var isFinishedPaging = false
fileprivate func fetchPostsWithUser(user: User) {
self.collectionView?.refreshControl?.endRefreshing()
let ref = Database.database().reference().child("posts").child(user.uid)
var query = ref.queryOrdered(byChild: "creationDate")
if posts.count > 0 {
let value = posts.last?.creationDate.timeIntervalSince1970
query = query.queryEnding(atValue: value)
}
query.queryLimited(toLast: 4).observeSingleEvent(of: .value, with: { (snapshot) in
guard var allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
allObjects.reverse()
if allObjects.count < 4 {
self.isFinishedPaging = true
} else {
self.isFinishedPaging = false
}
if self.posts.count > 0 && allObjects.count > 0 {
allObjects.removeFirst()
}
allObjects.forEach({ (snapshot) in
guard let dictionary = snapshot.value as? [String: Any] else { return }
var post = Post(user: user, dictionary: dictionary)
post.id = snapshot.key
self.posts.append(post)
})
self.collectionView?.reloadData()
}) { (err) in
print(err)
}
}
I simply want it to load more posts when the user scrolls down.
There may be a query issue or a potential logic issue. Lets assume you want to present posts to the user, with the most recent at the top of the list and allow the user to scroll down to see earlier posts.
Let's address both with an example:
We don't have your structure but keeping it super simple, suppose your posts have the following structure with creation dates
post_0
creation_date: "20180101"
post_1
creation_date: "20180102"
post_2
creation_date: "20180103"
post_3
creation_date: "20180104"
post_4
creation_date: "20180105"
post_5
creation_date: "20180106"
post_6
creation_date: "20180107"
post_7
creation_date: "20180108"
Here's your initial query, order by creation date, which will load the last 4 posts from the 5th to the 8th
var query = ref.queryOrdered(byChild: "creationDate")
Then subsequent queries are ordered by creation date but the ending value is not the creation date but the time elapsed since 1970 of the creation date.
let value = posts.last?.creationDate.timeIntervalSince1970
var query = ref.queryOrdered(byChild: "creationDate").queryEnding(atValue: value)
I would guess you just want to load the next 4 earlier posts. So as this sit in the array, they look like this:
20180108
20180107
20180106
20180105
One way to do that is the get the creationDate of the last post from your dataSource (which will be the oldest post)
20180105
Then query by creationDate, endingAt the creation date of the last post, getting 5 total posts, then remove the last one
20180101
20180102
20180103
20180104
20180105
then reversed
20180105
20180104
20180103
20180102
20180101
and remove the first
20180104
20180103
20180102
20180101
something like this
let lastD = self.postsArray.last
self.postsArray = []
let postsRef = self.ref.child("posts")
let queryRef = postsRef.queryOrdered(byChild: "creation_date")
let queryEndingRef = queryRef.queryEnding(atValue: lastD)
let queryLimitedRef = queryEndingRef.queryLimited(toLast: 5)
queryLimitedRef.observeSingleEvent(of: .value, with: { snapshot in
guard var thisArray = snapshot.children.allObjects as? [DataSnapshot] else { return }
thisArray.reverse()
thisArray.removeFirst()
for post in thisArray {
let theDate = post.childSnapshot(forPath: "creation_date").value as! String
self.postsArray.append(theDate)
}
})

Parse: selectKeys method not working

I'd like to retrieve only certain columns from Parse. But it downloads the whole objects instead:
let usersQuery = PFQuery(className: "_User")
usersQuery.whereKey("userId", containedIn: self.memberIds!) // Array of Strings containing the userIds
usersQuery.selectKeys(["email"])
usersQuery.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let users = objects as? [PFUser] {
print("objects: \(users)")
// prints whole object, not only "email" field
}
})
The output:
objects: [<PFUser: 0x7fb1095a7270, objectId: 9Ld9vRPoLZ, localId: (null)> {
email = "iphone5s#mail.com";
fullname = "iPhone 5S";
// ... other fields
}]

NSDate compare to Parse Data not querying records as expected

I have a column "checkInTime" in my Parse class that is of type Date.
I am trying to query any checkInTimes after a certain time
Here is the code I am using
func reloadCheckInView() {
checkIns.removeAll(keepCapacity: true)
let friendsListQuery = PFQuery(className: "Friends")
friendsListQuery.includeKey("friendId")
friendsListQuery.includeKey("user")
friendsListQuery.whereKey("friendId", equalTo: PFUser.currentUser()!)
friendsListQuery.whereKey("approved", equalTo: true)
friendsListQuery.findObjectsInBackgroundWithBlock {(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
let user = object["user"] as! PFObject
let now = NSDate()
print(now)
let BeforeNow = NSDate().dateByAddingTimeInterval(self.hourWindow * -3600)
print(self.hourWindow)
print(BeforeNow)
let checkInQuery = PFQuery(className: "LocationCheckIn")
checkInQuery.includeKey("user")
checkInQuery.whereKey("CheckInTime", greaterThan: BeforeNow)
checkInQuery.whereKey("user", equalTo: user)
//let subQuery = PFQuery.orQueryWithSubqueries([friendsListQuery, checkInQuery])
checkInQuery.findObjectsInBackgroundWithBlock {(results: [PFObject]?, error: NSError?) -> Void in
if error == nil {
//print(results)
for result in results! {
self.checkIns.append(result)
}
print(self.checkIns)
}
else {
}
}
}
}
else {
print(error)
}
}
}
and my prints which shows the calculations are working as expected..in this case 1 hr before now.
2015-10-17 15:23:49 +0000
1.0
2015-10-17 14:23:49 +0000
[]
and no records found in my query.
If I comment out
checkInQuery.whereKey("CheckInTime", greaterThan: BeforeNow)
the record is printed and you can see the checkIn time should pass my query but doesn't. Any ideas?
[<LocationCheckIn: 0x12903edb0, objectId: M7zTD3qiCL, localId: (null)> {
checkInPlaceId = "ChIJfc7vF8upVogRk20hK-LzaAM";
checkInPlaceName = "12434 Willingdon Rd";
checkInTime = "2015-10-17 14:26:00 +0000";
location = "<PFGeoPoint: 0x127ed52f0, latitude: 35.436804, longitude: -80.828736>";
user = "<PFUser: 0x127ed76d0, objectId: WCMmKTvNUC, localId: (null)>";
}]
And as I just read through my own question I see my error.. a typo
checkInQuery.whereKey("CheckInTime", greaterThan: BeforeNow)
should be
checkInQuery.whereKey("checkInTime", greaterThan: BeforeNow)

Parse query string ordering with locale swift

I am querying the database like below. However, orderbyAscending does not work properly, the accented letters are all sorted at the bottom. Is there any way Parse sorts it by locale? Or do I have to sort in the code? The string array is not long, about 40 words.
var query = PFQuery(className: RFIstanbulDistrictsClassKey)
query.whereKey(RFIstanbulDistrictsDistrictKey, notEqualTo: "")
query.orderByAscending(RFIstanbulDistrictsDistrictKey)
// constants are defined as follows:
// let RFIstanbulDistrictsClassKey = "IstanbulDistricts"
// let RFIstanbulDistrictsDistrictKey = "district"
It turns out I need to sort the array after loading it from Parse:
districts.removeAll(keepCapacity: true)
let query = PFQuery(className: RFIstanbulDistrictsClassKey)
query.whereKey(RFIstanbulDistrictsDistrictKey, notEqualTo: "")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
districts = objects.map { String($0[RFIstanbulDistrictsDistrictKey] as! String) }
districts.sort { return $0 < $1 } // sort ascending
}
}