Split nsarray to nsdictionary - ios

I am quering Parse and get an array back
PFQuery *query = [Points query];
[query whereKey:#"city" equalTo:[SharedParseStore sharedStore].chosenCity];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
I want to sort the array into a dictionary based on the district value that is in the Point object so that i can use a tableview with sections (district section names)
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
for (Points *point in objects) {
[dict setValue:point forKey:point.district];
}
block(dict, error);
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
The problem is it only adds 1 value of course
So to make it easy to understand:
The objects coming from Parse are Point objects with the following property's:
Name,District,City
I want to create a NSdictionary with the districts (so I need to collect them out of the objects first because I don't know them) as a key and the value for that key is an array with the points that are in that district.
I don't know beforehand what the districts will be. They will need to be picked from the objects array that is returned from Parse.
My final object I want to create is a nsdictionary with arrays of points for every distinct district(that is the key).
Example:
[#"districtA" : an array with Point objects that have districtA in their district property, etc etc]
what is the best way to do this because i really can't see how to do it ?

You answered your own question when you say:
I want to create a NSdictionary with the districts as a key and the
value for that key is an array with the points that are in that
district.
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableDictionary *dict = [#{} mutableCopy];
for (Points *point in objects) {
// if no point for that district was added before,
// initiate a new array to store them
if (![dict containsKey:point.district])
dict[point.district] = [#[] mutableCopy];
[dict[point.district] addObject:point];
}
block(dict, error);
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];

Related

Why is my NSMutable not being populated correctly when inserting objects from another NSArray?

I have a PFQuery that gets the current participants of a particular event:
PFQuery *getcurrentparticipants = [PFQuery queryWithClassName:#"Event"];
[getcurrentparticipants selectKeys:#[#"Participants"]];
[getcurrentparticipants whereKey:#"objectId" equalTo:ObjectID];
[getcurrentparticipants findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableArray *newParticipantsArray = [[NSMutableArray alloc]init];
if([objects[0] valueForKey:#"Participants"] == nil){ // If object retrieved in objects is null. If there are 0 participants
[newParticipantsArray addObject:PFUser.currentUser.username];
PFQuery *query = [PFQuery queryWithClassName:#"Event"];
[query getObjectInBackgroundWithId:self.ObjectID
block:^(PFObject *Event, NSError *error) {
Event[#"Participants"] = newParticipantsArray;
[Event incrementKey:#"Vacants" byAmount:[NSNumber numberWithInt:-1]];
[Event saveInBackground];
}];
}else{ // STEP 5
for(int i=0;i<objects.count;i++) {
[newParticipantsArray addObject:[[objects objectAtIndex:i] valueForKey:#"Participants"]];
}
[newParticipantsArray addObject:PFUser.currentUser.username];
NSLog(#"Part to upload %#", newParticipantsArray);
PFQuery *query = [PFQuery queryWithClassName:#"Event"];
[query getObjectInBackgroundWithId:self.ObjectID
block:^(PFObject *Event, NSError *error) {
Event[#"Participants"] = newParticipantsArray;
[Event incrementKey:#"Vacants" byAmount:[NSNumber numberWithInt:-1]];
[Event saveInBackground];
}];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
This is how the method works:
Create a PFQuery object
Query the Participants Class for an specific ObjectId
If no error, then we create a NSMutable array
If no participants are in Parse then we insert the current user as participant.
Else, insert all participants in the mutable array and add currentuser at the end of the array.
Then upload it again to Parse
My problem is in step 5:
When I perform the tasks in the else, the column in Parse looks like this :
[["Participant 1"],"Participant 2"]
But I would like to have it like this:
["Participant 1","Participant 2"]
What I have tried:
I tried things like putting the arrays like this. [newParticipantsArray addObject:[[objects objectAtIndex:i] valueForKey:#"Participants"]]; and similar combinations, of course without luck.
It’s hard to say for sure since I can’t see the structure of your data but are you sure the value held in
[[objects objectAtIndex:i] valueForKey: #“Participants”]
Is a single user and not itself an array of users? The plural key “participants” seems to suggest it’s an array of users which would also explain the result you’re getting.
If in fact the value returned for the "Participants" key is an array, you can add the objects in it to your mutable array by doing the following:
NSArray* participants = [[objects objectAtIndex:i] valueForKey:#"Participants"]
[newParticipantsArray addObjectsInArray:participants];
This uses the addObjectsInArray: method of NSMutableArray to add the objects from the old array into the new one.

What is the way in Parse (iOS) to get a query key value other than the id?

I am currently using parse to develop an iPhone app and I got this code:
I have a Class called "Event" and has a field called "EventName"
PFQuery *query = [PFQuery queryWithClassName:#"Event"];
[query selectKeys:#[#"EventName"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %lu scores.", (unsigned long)objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"%#", object.objectId);
}
}
}];
This works perfectly, but i get the object's IDs instead of the event names which is what i want.
EDIT :
So far I got this inside the IF statement
self.eventArray = [objects valueForKey:#"EventName"];
for(int i=0; i<10 ; i++){
NSLog(#"%#", eventArray[i]);
}
by doing that the question got solved.
All you have to do is use the objects array that was retuned from finding the objects and pass them into your array by using valueForKey.
So it would be
if (!error) {
self.yourEventNameArray = [objects valueForKey:#"EventName"];
}

Parse retrieve columns from 2 different objects

I've been using sql forever and i'm now stepping into using parse. I've reach a problem regarding the database structure. i have 2 objects called stores and users. i've added the stores objectId to each user so that i can identify which user is to which store. I do not know if there is another way, but this was what i could think of.
The issue is that i want to retrieve all the users and the store names which is connected to the users. How can achieve this using parse?
My code at the moment.
PFQuery *query = [PFQuery queryWithClassName:#"users"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (PFObject *object in objects) {
}
NSLog(#"%#", objects);
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
It does sound like the aim is to fetch related objects, but my understanding about how to do that differs from #Dima. You do it like this...
PFQuery *query = [PFQuery queryWithClassName:#"users"];
// this tells the query to eagerly fetch the related store object
[query includeKey:#"store"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// handle error, or ...
for (PFObject *object in objects) {
// object is from the users table, and object[#"store"] will contain
// the complete, related store object, eagerly fetched...
NSLog(#"the store object for %# is %#", object, object[#"store"]);
}
}];
If I understand correctly, you just want to fetch a related object? The documentation covers this.
You should be able to fetch a related object like this:
PFObject *store = user[#"store"]; // reference to related object but may need to be fetched
[store fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
// at this point you have fetched the store or you already have it
NSString *name = store[#"name"];
}];

How to fetch a PFObject with all it's fields and related objects in one go?

I have an NSArray of PFObjects and want to fetch all data related to the objects in this array in one go, so afterwards there is no need to make a new call to parse. How can I do this?
My answer is assuming the array you want is contained in a PFObject. You can query for this object and use the include key to include the array contained within that key.
PFQuery *query = [PFQuery queryWithClassName:#"<object's class name>"];
[query whereKey:#"objectId" equalTo:object.objectId];
[query includeKey:#"<array key>"];
If the objects in your array have pointers to other objects within them you can use the dot syntax to fetch everything at once.
[query includeKey#"<array key>.<pointer in object from array key>"];
Run the query once set up and you should retrieve an array of one object since objectIds are unique, within this object will be the array.
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error){
if(error){
// handle error
}else{
if([objects count] > 0){
PFObject *object = objects[0]; // Only one matching object to query
NSArray *array = object[#"<array key>"]; // Array you want
}
}
}];
You can use PFObject's methods family:
+(void)fetchAll:(NSArray*)objects
Check out PFObject documentation on those methods https://parse.com/docs/ios/api/Classes/PFObject.html#//api/name/fetchAll:
As far I got your query , this might be-
PFQuery *query = [PFQuery queryWithClassName:#"CLASS_NAME"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (!error && objects.count != 0)
{
NSLog(#"Successfully retrieved: %#", objects);
for(int i=0; i< objects.count; i--)
{
NSDictionary *dict = [objects objectAtIndex:i];
self.label = [dict objectForKey:#"PROPERTY_KEY"]; //Just example
/* Also modify this code as per you want to fetch properties of some or all */
/* Do as you want to with properties and also change key as per need of column/property you want */
}
}
}];
This way you will get array and also fetch fetch as you want.

Parse.com Query if String is Contained in Array

Working with recipes and I would like to query (search) based off of items in the recipe rather than the recipe names.
For example, multiple items may contain Chicken. I want to be able to search Chicken and see the Recipe Names that contain Chicken in the recipe.
Here's what I have tried:
- (void)filterResults:(NSString *)searchTerm
{
PFQuery * query = [PFQuery queryWithClassName:self.parseClassName];
NSArray * ingredientArray = [self.profileObject objectForKey:#"ingredients"];
[query whereKey:searchTerm containedIn:ingredientArray];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error)
{
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else
{
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:objects];
[self.searchDisplayController.searchResultsTableView reloadData];
}
}];
}
This code returns nothing and I get no errors.
Having difficulty figuring out the right way to set up the query.
Should this be solved as a query within a query?
Meaning:
Query through ingredients first, and then query on that to display the recipe name based on the previous query of recipes that contain the searchTerm.
I think you are misusing the [query whereKey:containedIn:] method. This is used to query for all PFObjects where the object for the key you specify is contained in the array you provide. Unless you made a new key for every recipe item, this won't work for your purposes, because none of your objects have a "Chicken" key, for instance.
First, I suggest you use a RecipeIngredient class in Parse with the following fields:
Pointer(Recipe) recipe //pointer to its Recipe object
Number amount //how much of unit
String unit //cup, gram, etc.
String ingredient //milk, flour, etc.
Now, you can simply query the RecipeIngredient class like so:
PFQuery * query = [PFQuery queryWithClassName:"RecipeIngredient"];
[query whereKey:"ingredient" equalTo:searchTerm];
[query includeKey:"recipe"]; //Fetches the Recipe data via the pointer
[query findObjectsInBackgroundWithBlock:^(NSArray *recipeIngredientObjects, NSError *error) {
if (!error) {
NSArray *recipes = [recipeIngredientObjects valueForKey:#"recipe"];
//update table data as needed
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
I had this problem last year sometime so I thought I would share the answer.
[query whereKey:#"ingredient" matchesRegex:searchTerm modifiers:#"i"];
That should do it for you. That helps with the case sensitivity.

Resources