I am a newbie to iOS, I am trying to get an array to work with a Parse.com query
userIDS = [[NSMutableArray alloc] init];
// example array that is from a UITableView
for(int i = 1; i <= 3; i++) {
[userIDS addObject:[NSString stringWithFormat:#"user%i", i]];
}
// Place user1, user2, user3 etc into a format like below so I can query multiple users.
NSArray *names = #[#"user1",
#"user2",
#"user3"];
[pushQuery whereKey:#"playerName" containedIn:names];
I have tried this
[pushQuery whereKey:#"playerName" containedIn:userIDS];
but that doesn't work.
edit below, below looks for "playerName"s user1, user2, user3 which is what I wanted.
userIDS = [[NSMutableArray alloc] init];
// example array that is from a UITableView
for(int i = 1; i <= 3; i++) {
[userIDS addObject:[NSString stringWithFormat:#"user%i", i]];
}
[pushQuery whereKey:#"playerName" containedIn:userIDS];
Your array must be of string values for this to work. Either you must have the PFObjects and create an array with their objectId or query for the column playerName, for this, you must have stringvalues of this column in an NSArray.
For example, if you don't have the PFObjects but know the names you are looking for:
NSArray *names = [[NSArray alloc] initWithObjects:#"PlayerOne", #"PlayerTwo", nil];
PFQuery * query = [PFQuery queryWithClassName:#"YourClass"];
[query whereKey:#"playerName" containedIn:names];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// Your objects here
}];
Hope it helps.
Related
I am making an app that registers users and allows them to add friends etc. So I have a LoginViewController where I retrieve the array of user's friends' objectIds when the login is successful. This function is called.
- (void) getFriendList
{
NSString * objectID = [PFUser currentUser].objectId;
NSLog(#"%#", objectID);
PFQuery *query = [PFUser query];
[query getObjectInBackgroundWithId:objectID block:^(PFObject *username, NSError *error) {
sharedClass.sharedInstance->retrievedFriends = username[#"friendsIds"];
friendListLoaded = YES;
[self getFriendsUsernames];
}];
Here i get an array object that contains object ids of all the friends this user has. As you can see when getFriendList is completed, it calls another function called GetFriendsUsernames. This function is supposed to retrieve profile pictures and usernames of those friends so I can populate the Friend List view later.
-(void) getFriendsUsernames
{
NSMutableArray * objectIDs = [[NSMutableArray alloc] initWithArray: sharedClass.sharedInstance->retrievedFriends];
PFQuery *query = [PFUser query];
int friendsCount = [objectIDs count];
for(int i = 0; i<=friendsCount;i++)
{
[query getObjectInBackgroundWithId:objectIDs[i] block:^(PFObject *username, NSError *error) {
[sharedClass.sharedInstance->friendsUsernames addObject:username[#"username"]];
[sharedClass.sharedInstance->friendsProfilePictures addObject:username[#"ProfilePicture"]];
}];
NSLog(#"%#", sharedClass.sharedInstance->friendsUsernames );
}
}
But this seems to be unsuccessful because nothing is logged on the console where it should log username of retrieved friend whenever one query gets finished. Am I doing this the right way? My array count is right so loop runs to the number of friends a user has. It also prints the username of first object in objectIds array if i put the logging command in the loop.
Your NSLog runs immediately after your query objects are queued for execution. Therefore, even if the code is running correctly (and I suspect it might not be), you'll never get the correct results you're after logged to the console.
If you have your Parse classes designed in a certain way, you could collapse this into 1 query by using the include method on PFQuery. This assumes that you've created an array of Pointers on your User object, named "friends". If you actually store the objectId (i.e., the string value) of each friend, this code won't work.
I'm not using Swift yet, so here's how I'd write this query in Objective-C:
- (void)getFriendList {
PFUser *currentUser = [PFUser currentUser];
PFQuery *query = [PFUser query];
[query whereKey:#"objectId" equalTo:currentUser.objectId];
[query includeKey:#"friends.username"];
[query includeKey:#"friends.ProfilePicture"];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *user, NSError *error) {
if (error != nil) {
// Process the error
} else }
// You've got your user and the data you wanted
}
}];
}
Found it. Not the prettiest way out there but well it does what i want. gets me arrays of usernames and profile pictures of every objectID contained in array of friends.
NSMutableArray * objectIDs = [[NSMutableArray alloc] initWithArray: sharedClass.sharedInstance->retrievedFriends];
PFQuery *query = [PFUser query];
PFFile * imageFile;
//UIImage *profilePictureData;
int friendsCount = [objectIDs count];
for(int i = 0; i<friendsCount;i++)
{
PFObject * username = [query getObjectWithId:objectIDs[i]];
[sharedClass.sharedInstance->friendsUsernames addObject:username[#"username"]];
[sharedClass.sharedInstance->friendsEmailAdresses addObject:username[#"email"]];
//NSLog(#"%#",username[#"ProfilePicture"]);
imageFile = [username objectForKey:#"ProfilePicture"];
NSData *imageData = [imageFile getData];
UIImage *imageFromData = [UIImage imageWithData:imageData];
[sharedClass.sharedInstance->friendsProfilePictures addObject:imageFromData];
NSLog(#"%#", sharedClass.sharedInstance->friendsUsernames );
}
I want to make my PFQuery come in a random order, so the next time I'm creating the same PFQuery with limit it won't return the same objects as the first one.
PFQuery *query = [PFUser query];
[query orderBy...]; //Is there a randomOrder method?
//Or a workaround to get random order?
[query setLimit:10];
I need this to be in a random order every time, or else the PFQuery will contain the same 10 objects everytime
You can't change the ordering of data returned in the query, but you can use paging to change the first object that is returned - so you could do something like this (it is based on the ToDo sample code from Parse but it will work for any object) -
PFQuery *query =[PFQuery queryWithClassName:#"Todo"];
NSInteger count=[query countObjects];
NSInteger skip = arc4random_uniform(count-10);
query.skip=skip;
query.limit=10;
NSArray *results=[query findObjects];
NSLog(#"object count=%d",results.count);
for (PFObject *object in results) {
NSLog(#"text=%#",object[#"text"]);
}
You can now retrieve your 10 objects. for any given skip count they will be in the same order, but you could randomise the order after you retrieved the 10 items. Simply put them into an NSMutableArray and use technique in this answer - Re-arrange NSArray/MSMutableArray in random order
Note that this code isn't optimal as it doesn't perform the fetch tasks on the background thread. To use background threads you would use something like the following -
PFQuery *query =[PFQuery queryWithClassName:#"Todo"];
[query countObjectsInBackgroundWithBlock:^(int number, NSError *error) {
query.skip=arc4random_uniform(number-10);;
query.limit=10;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"An error occurred - %#",error.localizedDescription);
}
else {
NSLog(#"object count=%d",objects.count);
for (PFObject *object in objects) {
NSLog(#"text=%#",object[#"text"]);
}
}
}];
}];
PFQuery does not support random order but you can workaround this by creating an increasing index field to each object
Then given that you know the maxIndexin the table you can generate random indices as the following:
- (NSArray *)generateRandomIndices:(int)maxIndex limit:(int)limit {
NSMutableArray *indices = [[NSMutableArray alloc] initWithCapacity:limit];
for (int i=0; i<limit; i++) {
int randomIndex = arc4random() % maxIndex;
[indices addObject:[NSNumber numberWithInt:randomIndex]];
}
return indices;
}
Now you can query your class by using INpredicate
NSArray *randomIndices = [self generateRandomIndices:maxIndex limit:10];
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"index IN %#", randomIndices];
PFQuery *query = [PFQuery queryWithClassName:#"className" predicate:predicate];
PFQuery don't give random objects. You can get all objects then randomize to get any 10 objects from it and show it.
I have data on database like this.
["{37.331622, -122.030337}","{37.331593, -122.03051}","{37.331554, -122.030681}","{37.331383, -122.030757}","{37.33108, -122.030772}","{37.330798, -122.030729}","{37.330636, -122.030636}"]
Then i try to query data from database by following code.
- (void)updateLocations {
CGFloat kilometers = self.radius/1000.0f;
//PFUser *user = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"Session"];
[query whereKey:#"objectId" equalTo:#"t2udAri048"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSLog(#"objects %#",objects);
NSLog(#"path %#",[objects valueForKey:#"Path"]);
NSArray *pointsArray = [objects valueForKey:#"Path"];;
NSInteger pointsCount = pointsArray.count;
CLLocationCoordinate2D pointsToUse[pointsCount];
for(int i = 0; i < pointsCount; i++) {
CGPoint p = CGPointFromString(pointsArray[i]);
pointsToUse[i] = CLLocationCoordinate2DMake(p.x,p.y);
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:pointsToUse count:pointsCount];
[self.mapView addOverlay:myPolyline];
//NSLog(#"Drawed %#",pointsArray);
}
}];
}
I get the value of [objects valueForKey:#"Path"]
(
(
"{37.331622, -122.030337}",
"{37.331593, -122.03051}",
"{37.331554, -122.030681}",
"{37.331383, -122.030757}",
"{37.33108, -122.030772}",
"{37.330798, -122.030729}",
"{37.330636, -122.030636}"
) )
But i want it to
(
"{37.331622, -122.030337}",
"{37.331593, -122.03051}",
"{37.331554, -122.030681}",
"{37.331383, -122.030757}",
"{37.33108, -122.030772}",
"{37.330798, -122.030729}",
"{37.330636, -122.030636}"
)
What should i do?
It looks as if objects is an array of one element, which is an object with the "Path"
property. In that case you should replace
NSArray *pointsArray = [objects valueForKey:#"Path"];
by
NSArray *pointsArray = [objects[0] valueForKey:#"Path"];
In your example you have the objectId. If that is the case, you use getObjectWithId. This will return only the object you want.
PFQuery *query = [PFQuery queryWithClassName:#"Session"];
[query getObjectWithId:#"hr46gjh45"];
Your example returns an array of objects; in this case the array has only one object (but it is still an array). In that case you must first retrieve the object from the array.
I have table name "Events". In that table I have a column of type array of string. I'm struggling with how I can delete only one element from that column. Consider the image below, I want to delete all the occurrences of "iYYeR2a2rU" from the "usersIncluded" column, without deleting the rows.
I've used the removeObject:(id) forKey:(NSString *) and it didn't work.
This is how I'm trying to achieve it:
PFQuery *query = [PFQuery queryWithClassName:#"Events"];
NSArray *eventObjects = [query findObjects];
[query whereKey:#"usersIncluded" equalTo:[self.uniqeFriendList objectAtIndex:indexPath.row]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error){
for (int i = 0; i<objects.count; i++) {
PFObject *event = [eventObjects objectAtIndex:i];
[event removeObject:[self.uniqeFriendList objectAtIndex:indexPath.row] forKey:#"usersIncluded"];
}
}];
}
The self.uniqeFriendList is a mutable array containing the ids that I want to delete from the 'usersIncluded' column.
Thanks in Advance
I think you're using the right method (removeObject:forKey: should do exactly what you want) but I think you're working with objects from the wrong array. You're performing your query twice, and within the findObjectsInBackgroundWithBlock: you're working with the array from the first time you called it... Try this:
PFQuery *query = [PFQuery queryWithClassName:#"Events"];
[query whereKey:#"usersIncluded" equalTo:[self.uniqeFriendList objectAtIndex:indexPath.row]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error){
for (int i = 0; i <objects.count; i++) {
PFObject *event = [objects objectAtIndex:i]; // note using 'objects', not 'eventObjects'
[event removeObject:[self.uniqeFriendList objectAtIndex:indexPath.row] forKey:#"usersIncluded"];
}
[PFObject saveAll:objects];
}];
}
Anyone know how to shrink this, so that I don't have to run querys in the main thread in the QueryForTable method? I'm using Parse.com
//Find who are the users following (RELATIONSHIP OBJECT)
PFQuery *followeesQuery = [PFQuery queryWithClassName:#"Relationship"];
[followeesQuery whereKey:#"Follower" equalTo:[PFUser currentUser]];
NSArray *followees = [followeesQuery findObjects];
//Filter followees
self.followees = [[NSMutableArray alloc] initWithCapacity:[followees count]];
for (int i = 0; i < [followees count]; i++) {
PFObject *followee = followees[i];
PFUser *user = (PFUser *)[followee objectForKey:#"User"]; //USER OBJECT
[self.followees addObject:user];
}
PFQuery *nearbyPhotosQuery = [PFQuery queryWithClassName:#"Photo"]; //PHOTO OBJECT
[nearbyPhotosQuery whereKey:#"User" notContainedIn:self.followees];
[nearbyPhotosQuery whereKey:#"Location" nearGeoPoint:self.userCurrentLocation withinKilometers:10];
PFQuery *followersPhotoQuery = [PFQuery queryWithClassName:#"Photo"]; //PHOTO OBJECT
[followersPhotoQuery whereKey:#"User" containedIn:self.followees];
NSMutableSet *set = [NSMutableSet setWithArray:[nearbyPhotosQuery findObjects]];
[set addObjectsFromArray:[followersPhotoQuery findObjects]];
NSArray *targetPhotoObjects = [set allObjects];
NSMutableArray *targetIDs = [[NSMutableArray alloc] initWithCapacity:[targetPhotoObjects count]];
for (int i = 0; i < [targetPhotoObjects count] ; i++) {
PFObject *photoObject = targetPhotoObjects[i];
[targetIDs addObject:photoObject.objectId];
}
PFQuery *targetPhotoQuery = [PFQuery queryWithClassName:#"Photo"];
[targetPhotoQuery whereKey:#"objectId" containedIn:targetIDs];
return targetPhotoQuery;
If I read this correctly, you want a query for all photos by followers or near you. Why not use:
PFQuery *followeesQuery = [PFQuery queryWithClassName:#"Relationship"];
[followeesQuery whereKey:#"Follower" equalTo:PFUser.currentUser];
PFQuery *followeesPhotosQuery = [PFQuery queryWithClassName:#"Photo"];
[followeesPhotosQuery whereKey:#"User" matchesKey:#"User" inQuery:followeesQuery];
PFQuery *nearbyPhotosQuery = [PFQuery queryWithClassName:#"Photo"];
[nearbyPhotosQuery whereKey:#"Location"
nearGeoPoint:self.userCurrentLocation
withinKilometers:10];
return [PFQuery orQueryWithSubqueries:#[followeesPhotosQuery, nearbyPhotosQuery]];
This is a query which matches what you're looking for which doesn't require server-side trips to create. You may need to play with the maximum number of elements returned by inner queries if you expect more than 100 elements to be returned along any step in the process; each query along the way is subject to its own query limit.