Is there any way to do a query in Parse to get the most recently added PFObject type?
I know that I can do a query with a greater than criteria, but it would be very useful if there was a function to get the most recent object added when no date is known.
Just add a descending order on createdAt and get the first object:
PFQuery *query = [PFQuery queryWithClassName:#"YourClassName"];
[query orderByDescending:#"createdAt"];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
// code
}];
In Swift:
var query = PFQuery(className: "YourClassName")
query.orderByDescending("createdAt")
query.getFirstObjectInBackgroundWithBlock {(object: PFObject?, error: NSError?) -> Void in
// code
}
This may not address the use case in question. I often want to get back the objectId of the object i just added in code. While it might be automatically possible, i have missed any info in this regard. So i usually have my own unique identifier that i add, and then retrieve the object by that identifier in the async block.. thus getting the objectId..
Related
When I run the following
PFQuery *query = [PFQuery queryWithClassName:#"EventsTable"];
[query setCachePolicy:kPFCachePolicyNetworkOnly];
// Only active items
[query whereKey:#"active" equalTo:[NSNumber numberWithBool:YES]];
// Query by distance from current location
[query whereKey:#"geoLocation" nearGeoPoint:currentLocation];
// Only download objects that match the appropriate key
[query whereKey:#"keyedItems" containedIn:keysArray];
[query findObjectsInBackgroundWithBlock:^(NSArray *eventArray, NSError *error) {
It goes into an infinite loop with no error messages. But If I drop the nearGeoPoint it works fine, or if I keep the nearGeoPoint but drop the active it also works. But dropping the containedIn and keeping the nearGeoPoint and the active also fail the same way. I have also tried rearranging the order but no luck.
Any suggestions?
At first I wasn't able to find an error message so I assumed that it was stuck in the block, but alas here it is
Error: Error Domain=Parse Code=1 "{"code":1,"message":"Internal server error."}" UserInfo={error={"code":1,"message":"Internal server error."}, NSLocalizedDescription={"code":1,"message":"Internal server error."}, code=1} {
NSLocalizedDescription = "{\"code\":1,\"message\":\"Internal server error.\"}";
code = 1;
error = "{\"code\":1,\"message\":\"Internal server error.\"}";
}
This sounds like a parse server error to me - Is that correct?
The issue is that the table was so large it was unable to handle the query. The fix was just as mentioned above - to create an index. In this case I was able to turn on automatic indexing in the MongoDB. That solved the problem.
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
So , I've made a class called Posts in Parse.com.. This is the image of the class Posts
here you can see in objectId column there are objectIds of all the Posts and in the column likes I'm saving the ObjectIds of users who is liking the post.. so basically if a user tap on unlike button the current user's Id should be deleted . this is my current code:
var query:PFQuery = PFQuery(className: "Posts")
query.whereKey("objectId", equalTo: postData.objectId!)
query.whereKey("likes", equalTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
object.deleteInBackground()
}
}
})
but it deletes the whole row not the user id of current user..
You can use removeObject:forKey: to only remove this single object from the array. After doing this, call saveInBackground to save the changes back to the server.
See also: https://www.parse.com/docs/ios/guide#objects-arrays
I believe you are storing userID in your likes array as strings instead of pointers.
In your code, the key "likes" is an array type, but you want to query an objectId which is a string type, clearly parse won't find any column matches this query.
so in your case, you want to remove one of the strings in your likes array(objective c code)
PFQuery *query = [PFQuery queryWithClassName#"Posts"];
[query whereKey:#"objectId" equalTo:postData.objectId];
[query findObjectsInBackgroundWithBlock:^(NSArray *object, NSError *error)
{
if (! error)
{
//get the post object, index 0 because each post has 1 unique ID
PFObject *thisObject = [object objectAtIndex:0];
//get the likes array
NSMutableArray *array = [[NSMutableArray alloc]initWithArray:thisObject[#"likes"]];
[array removeObject:/* your user id*/];
//save the new array
[thisObject setObject:array forKey:#"likes"];
[thisObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error){
if (succeeded)
{
//success
}
}];
}
}];
I have used your method to remove a users objectID from another users friends list and instead add it to the users blocked friends list, both are in an array on parse. Thanks
let cell = tableView.cellForRow(at: indexPath) as! cell
let theUsersID = cell.theObjectID.text!
PFUser.current()?.addUniqueObjects(from: [theUsersID], forKey: "friendList")
PFUser.current()?.saveInBackground()
PFUser.current()?.removeObjects(in: [theUsersID], forKey: "blockFriend")
PFUser.current()?.saveInBackground()
self.usernames.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
I've looked all over and have found no joy. I was wondering if someone could help me figure out how to retrieve a random object from a class on parse.com using swift in an iOS app. By no means am I asking someone to write my code, because then what would I learn, but I was wondering if someone could maybe provide a generic example that I could adapt to my project and future projects.
Let's say the class is called ParseClass, and I will need to populate three variables with data from the object in parse., A, B, C -- two with strings, one as an array of strings. Let's say there are ... idk ... 50 objects in the parse class, and I need to retrieve them one at a time randomly.
Logically, I get it ... I need to do a count of the objects in the parseclass, then get a random number from that count, and then use that number to retrieve the object somehow (either directly from parse using a skip random query limit 1, or maybe by getting all the objects into an array (whichever is the best/most efficient code). I just don't know how to format/write the code in swift. Any one think they could help me (and many others apparently) with some generic code I could adapt to my specific project??
Here is some generic code ... I can start it -- I got a basic idea of how it should be, I just don't know swift well enough to complete the block.
var A : String!
var B : [String]!
var C : String!
var query : PFQuery = PFQuery(className: "ParseClass")
query.findObjectsInBackgroundWithBlock {
(objects : [AnyObject]!, error : NSError!) -> Void in
//now what?
I've seen this in other questions here, but I don't know how to incorporate it.
let randomSkip = arc4random_uniform(count)
query.skip = randomSkip, and query.limit = 1.
Any help on this would be greatly appreciated.
Oh -- just saw this in another thread ... it's basically doing what I need, but in objective C and it looks like with only 2 variables... could someone help me rewrite in swift? Sorry to be so loquacious ... the burden of a novice. I promise as I grow more adept, I will help other novices most sympathetically. :-)
- (void)randomQuestion:(void (^)(NSString *question, NSArray *answers))completion {
PFQuery *countQuery = [PFQuery queryWithClassName:#"ParseClass"];
[countQuery countObjectsInBackgroundWithBlock:^(int count, NSError *error) {
NSInteger randomSkip = arc4random_uniform(count);
PFQuery *query = [PFQuery queryWithClassName:#"ParseClass"];
query.skip = randomSkip;
query.limit = 1;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if (objects.count) {
PFObject *ParseClassObject = objects[0];
NSString *A = ParseClassObject[#"A"];
NSArray *B = ParseClassObject[#"B"];
completion(A, B);
} else {
NSLog(#"no error, but no ParseClass objects found");
}
} else {
NSLog(#"there was an error %#", error);
completion(nil, nil);
}
}];
}];
}
ObjectHolder should be objectHolder, or objects because it's a parameter name.
Your count for arc4random_uniform would be objects.count.
Downloading the objects and randomly accessing them locally will be most efficient if you need to display all of them anyway. Multiple downloads isn't great.
You're going to run into size limits eventually as the download row count is limited. Perhaps you could download pages and treat the items in each page as a separate collection to view randomly...
So, you wouldn't be using skip or limit, you would just be accessing elements in the objects array.
Removing the items from the array after you've used them is easiest. Or you can randomly sort the array so you don't need to remove
One way you can do it is to set another key called e.g. questionsNumber and each question will be be in that questionNumbers row. And then query the number from the arc4random_uniform(count) so something like this:
var query = PFQuery(className: "ParseClass")
let randomNumber = arc4random_uniform(count)
var randomNumberCast = Int(randomNumber)
query.whereKey("questionNumber", equalTo: randomNumberCast)
query.getFirstObjectInBackgroundWithBlock { (object: PFObject!, error: NSError!) -> Void in
if error == nil {
let questions = object["questions"] as String //This will equal your question at random.
}
}
i'm using Parse.com I wanted to ask you something if you can ... How do I delete from the list the total number of users CurrentUser? I would avoid that the report will also be made with oneself: D Thank you all
Perfect Guys .. then I found the method ... In layman's terms to exclude the PFUser Current User from a query to show only the App users but not the CurrentUser is just the use of notEqualTo in the query but it should be associated with the string that we want to remove from the query
I hope this can help other people :)
Do not pay too much attention to the constants: D
PFQuery * query = [self.RelazioniUtenti query];
[query whereKey: FF_USER_NOMECOGNOME notEqualTo: [[PFUser currentUser] objectForKey: FF_USER_NOMECOGNOME]];
[query orderByAscending: FF_USER_NOMECOGNOME];
[query findObjectsInBackgroundWithBlock: ^ (NSArray * objects, NSError * error) {