Parse relationships and searches specific pfQuery PFObject - ios

I want to use as the backend of my app Parse, and suppose that I have a class with different restaurants, menus for each restaurant and for each menu different products, I have a class Place, Menu, Product and MenuItems:
The MenuItem class has:
Pointe menu
Pointer product
The Menu class:
Pointer place
Once chosen restaurant have to show all products for that restaurant:
My Code:
PFQuery *query = [PFQuery queryWithClassName:#"Places"];
[query whereKey:#"name" equalTo:PlaceSelect];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
PFObject *Menu;
if (!error)
{
for (PFObject *ob in objects)
{
Menu = ob;
}
}
PFQuery *query1 = [PFQuery queryWithClassName:#"Menus"];
[query1 whereKey:#"place" equalTo:Menu];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects2, NSError *error2) {
PFObject *MenuItems;
if (!error2)
{
for (PFObject *ob2 in objects2)
{
MenuItems = ob2;
}
}
PFQuery *query2 = [PFQuery queryWithClassName:#"MenuItems"];
[query2 whereKey:#"menu" equalTo:MenuItems];
[query2 selectKeys:#[#"product"]];
[query2 findObjectsInBackgroundWithBlock:^(NSArray *objects3, NSError *error3) {
PFObject *Products;
if (!error3)
{
for (PFObject *ob3 in objects3)
{
Products = ob3;
NSLog(#" %# ",Products);
}
I get related products but when I want to filter by type: drinks, starters, etc... It gives me all the products of all places them...
PFQuery *retrievedDrink = [PFQuery queryWithClassName:#"Products"];
[retrievedDrink whereKey:#"type" equalTo:#"drink"];
[retrievedDrink whereKey:#"objectId" equalTo:Products.objectId];
[retrievedDrink findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
DrinksArray = [[NSArray alloc] initWithArray:objects];
NSLog(#"numero de productos Drinks= %i ",[DrinksArray count]);
}];
Thanks in advance, if anyone knows a way to more efficiently please I would like to clarify my doubts

Get rid of this line
[retrievedDrink whereKey:#"objectId" equalTo:Products.objectId];
That is returning all your objects.
You have a duplicate array of your objects that is not needed, and also, do an error check.
This should find all the drinks stored in your Parse class, store them in an array called objects and allow you to query that array in your findObjectsInBackgroundWithBlock
PFQuery *retrievedDrink = [PFQuery queryWithClassName:#"Products"];
[retrievedDrink whereKey:#"type" equalTo:#"drink"];
[retrievedDrink findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSLog(#"numero de productos Drinks= %i ",[objects count]);
}
}];

Related

IOS Parse is my nested query a good solution for comparing an object with a pointer?

Currently, I am querying the database twice to achieve a list of all users nearby who are not already being followed by the current user. Here is my nested query:
// List of all users being followed by the current user
PFQuery *followingActivitiesQuery = [PFQuery queryWithClassName:kFTActivityClassKey];
[followingActivitiesQuery whereKey:kFTActivityTypeKey equalTo:kFTActivityTypeFollow];
[followingActivitiesQuery whereKey:kFTActivityFromUserKey equalTo:[PFUser currentUser]];
[followingActivitiesQuery setCachePolicy:kPFCachePolicyNetworkOnly];
[followingActivitiesQuery includeKey:kFTActivityToUserKey];
[followingActivitiesQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableArray *followedUserIds = [[NSMutableArray alloc] init];
// Obtain an array of object ids for all users being followed
for (PFObject *object in objects) {
PFUser *followedUser = [object objectForKey:kFTActivityToUserKey];
[followedUserIds addObject:followedUser.objectId];
}
PFGeoPoint *geoPoint = [[PFUser currentUser] objectForKey:kFTUserLocationKey];
// List of all users within 50 miles that are not already being followed
PFQuery *followUsersByLocationQuery = [PFQuery queryWithClassName:kFTUserClassKey];
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey notEqualTo:[PFUser currentUser].objectId];
[followUsersByLocationQuery whereKey:kFTUserLocationKey nearGeoPoint:geoPoint withinMiles:50];
[followUsersByLocationQuery whereKeyExists:kFTUserLocationKey];
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey notContainedIn:followedUserIds];
[followUsersByLocationQuery setLimit:100];
[followUsersByLocationQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objects = objects;
[self.tableView reloadData];
}
}];
}
}];
My question is, is this a viable solution? I feel guilty about having to query the server twice in order to achieve this, but I was not able to do it all in one query. I could not compare a parse pointer from the ActivityClass to the Users class, since the Users class is the class being pointed to, and because of this I couldn't think of a way to do it all in one query.
You're in luck - this can be done in a single query using the whereKey:doesNotMatchKey:inQuery: method of PFQuery.
Parse will treat this as a single, compound query against the database. Totally guilt-free :)
Try this instead:
// List of all users being followed by the current user
PFQuery *followingActivitiesQuery = [PFQuery queryWithClassName:kFTActivityClassKey];
[followingActivitiesQuery whereKey:kFTActivityTypeKey equalTo:kFTActivityTypeFollow];
[followingActivitiesQuery whereKey:kFTActivityFromUserKey equalTo:[PFUser currentUser]];
[followingActivitiesQuery setCachePolicy:kPFCachePolicyNetworkOnly];
[followingActivitiesQuery includeKey:kFTActivityToUserKey];
PFGeoPoint *geoPoint = [[PFUser currentUser] objectForKey:kFTUserLocationKey];
// List of all users within 50 miles that are not already being followed
PFQuery *followUsersByLocationQuery = [PFQuery queryWithClassName:kFTUserClassKey];
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey notEqualTo:[PFUser currentUser].objectId];
[followUsersByLocationQuery whereKey:kFTUserLocationKey nearGeoPoint:geoPoint withinMiles:50];
[followUsersByLocationQuery whereKeyExists:kFTUserLocationKey];
//The next line is your new compound query
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey doesNotMatchKey:#"objectId" inQuery:followingActivitiesQuery];
[followUsersByLocationQuery setLimit:100];
[followUsersByLocationQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objects = objects;
[self.tableView reloadData];
}
}];

Parse Query - cannot process more than one whereKey:doesNotMatchKey:inQuery

I was trying this
PFQuery *allDealsQuery = [Deal query];
PFRelation *favoritedDealsRelation = [user objectForKey:#"favoritedDeals"];
PFQuery *favoritedDealsQuery = [favoritedDealsRelation query];
PFRelation *redeemedDealsRelation = [user objectForKey:#"redeemedDeals"];
PFQuery *redeemedDealsQuery = [redeemedDealsRelation query];
[allDealsQuery whereKey:#"objectId" doesNotMatchKey:#"objectId" inQuery:favoritedDealsQuery];
//Parse does not support more than 2 where queries???
[allDealsQuery whereKey:#"objectId" doesNotMatchKey:#"objectId" inQuery:redeemedDealsQuery];
[allDealsQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
onSuccess(objects);
}
else {
onError(error);
}
}];
When I tried to use two queries, the answer was different from what was expected.
So should I use be using only one doesNotMatchKey query?
Try referencing parse documentation on Compound Queries:
https://parse.com/docs/ios_guide#queries-compound/iOS
Compound Queries
If you want to find objects that match one of several queries, you can use orQueryWithSubqueries: method. For instance, if you want to find players with either have a lot of wins or a few wins, you can do:
PFQuery *lotsOfWins = [PFQuery queryWithClassName:#"Player"];
[lotsOfWins whereKey:#"wins" greaterThan:#150];
PFQuery *fewWins = [PFQuery queryWithClassName:#"Player"];
[fewWins whereKey:#"wins" lessThan:#5];
PFQuery *query = [PFQuery orQueryWithSubqueries:#[fewWins,lotsOfWins]];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
// results contains players with lots of wins or only a few wins.
}];

IOS Parse include key query

I am trying to print the name of a category using Parse in iOS and Objectve-C. Thanks for looking. Let me know if you have any questions.
CategoryInBudget Table
category(pointer)
amount(number)
user(pointer)
Category Table
name(string)
Here is my code:
PFQuery *query = [PFQuery queryWithClassName:#"CategoryInBudget"];
[query whereKey:#"user" equalTo:[PFUser currentUser]];
[query includeKey:#"Category"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
for (PFObject *object in objects) {
NSLog(#"%#", object[#"Category"][#"name"];
}
}];

Fetch objectId from a User in parse

i'm new to parse and i'm trying to fetch a user objectId, but whatever i cant seem to return the objectId. I can easily return the username. this is my query:
PFQuery *query = [PFUser query];
[query whereKey:#"username" equalTo:[[PFUser currentUser] objectForKey:#"username"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if (objects.count) {
NSLog(#"%#", [objects lastObject]);
}
}
}];
This returns something like this:
<PFUser:9dcc65tsdr:(null)> {
username = AEleQFdBx9jdtypfsQmLtzAvW;
}
How do i return the objectId which is between PFUser and (null)?
You can use object.objectId like this:
PFQuery *query = [PFUser query];
[query whereKey:#"username" equalTo:[[PFUser currentUser] objectForKey:#"username"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if (objects.count) {
for (PFObject *object in objects){
NSLog(#"Object ID: %#", object.objectId);
}
}
}
You can also use this: [[PFUser currentUser]objectId] much faster and works much better because you don't have to run a whole PFQuery.

Search Feature Parse IOS

I would like to make a search feature that queries two different key from the same class. What kind of regular expression could I use that return the most accurate values. Example:
- (void)searchTableList {
[self.results removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName:#"TC"];
CLLocationCoordinate2D coordinate = [self.delegate.location coordinate];
PFGeoPoint *geoPoint = [PFGeoPoint geoPointWithLatitude:coordinate.latitude
longitude:coordinate.longitude];
PFQuery *query1 = [PFQuery queryWithClassName:#"TC"];
[query1 setLimit:1000];
[query1 whereKey:#"location"
nearGeoPoint:geoPoint
withinKilometers:5];
[query1 whereKey:#"courses" matchesRegex:[NSString stringWithFormat:#"%#",[self.searchBar.text lowercaseString]]];
[query1 whereKey:#"owner" notEqualTo:[PFUser currentUser].username];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
for( PFObject * object in objects)
{
[self.results addObject:object];
}
[query setLimit:1000];
[query whereKey:#"location"
nearGeoPoint:geoPoint
withinKilometers:5];
[query whereKey:#"owner" matchesRegex:[NSString stringWithFormat:#"%#",[self.searchBar.text lowercaseString]]];
[query whereKey:#"owner" notEqualTo:[PFUser currentUser].username];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
for( PFObject * object in objects)
{
[self.results addObject:object];
}
[self.tableView reloadData];
}];
}];
}
How could I take these two queries and order them in such a way that the most accurate information has priority.
If you want to find objects that match one of several queries, you can use orQueryWithSubqueries: method. For instance, if you want to find players with either have a lot of wins or a few wins, you can do:
PFQuery *lotsOfWins = [PFQuery queryWithClassName:#"Player"];
[lotsOfWins whereKey:#"wins" greaterThan:#150];
PFQuery *fewWins = [PFQuery queryWithClassName:#"Player"];
[fewWins whereKey:#"wins" lessThan:#5];
PFQuery *query = [PFQuery orQueryWithSubqueries:#[fewWins,lotsOfWins]];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
// results contains players with lots of wins or only a few wins.
}];

Resources