Parse.com -- Add on values from a second class/object - ios

So I'm using Parse.com and their AnyPic app as a starting point. It's an Instagram clone. However, unlike Instagram, the comments for pictures aren't included on home page. You have to tap the picture and it brings up a DetailsVC with the commments. This is the first thing I'm trying to change.
I'm new to Parse (and backends in general) and am having trouble trying to modify the query to return the comments. If you've used AnyPic, you know that the comments aren't saved in the Photo class but in a separate Activity class:
Activity.type would equal comment and Activity.content would be the comment text.
SO, the VCs in AnyPic subclass Parse's PFQueryTableViewController, overriding the queryForTable method to fetch data. Here's the queryForTable for their AccountVC, which returns ONLY the photos:
- (PFQuery *)queryForTable {
if (!self.user) {
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
[query setLimit:0];
return query;
}
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyNetworkOnly;
if (self.objects.count == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
[query whereKey:kPAPPhotoUserKey equalTo:self.user];
[query orderByDescending:#"createdAt"];
[query includeKey:kPAPPhotoUserKey];
return query;
}
And the queryForTable for the DetailsVC, which will return comments for the photo object passed to it in self.photo:
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
[query whereKey:kPAPActivityPhotoKey equalTo:self.photo];
[query includeKey:kPAPActivityFromUserKey];
[query whereKey:kPAPActivityTypeKey equalTo:kPAPActivityTypeComment];
[query orderByAscending:#"createdAt"];
[query setCachePolicy:kPFCachePolicyNetworkOnly];
// If no objects are loaded in memory, we look to the cache first to fill the table
// and then subsequently do a query against the network.
//
// If there is no network connection, we will hit the cache first.
if (self.objects.count == 0 || ![[UIApplication sharedApplication].delegate performSelector:#selector(isParseReachable)]) {
[query setCachePolicy:kPFCachePolicyCacheThenNetwork];
}
return query;
}
I just can't wrap my head around how to combine the two queries into one and have it return photo objects with comment values attached.
I've thought to just run a separate query for the comments in tableView:numberOfRowsInSection: once queryForTable returns a set of photos, but I'm thinking it's better if I let Parse's queryForTable handle it in case there's some caching going on that might be useful.

Related

How to access fields of a pointer's value on parse.com with iOS?

I am designing a database. According to documentation, when number of relationships are greater than 100 and there is extra fields, I must design a Join Table. I designed this Join Table by having two pointer value.
This pointer value is pointing to _User. Later I need only rows for currUser.
This pointer value is the objectId of another table which is an entity. My question is, how can I write a query to return objects for this table in queryfortable.
Let's say:
Table _User
Table Entity
Table Join ---> objectId Pointer1(_User) Pointer2(Event)
This look like this:
This is what I have tried so far:
First I tried in viewDidLoad to get array of invitedUser from cloud and later in queryForTable:
PFQuery *query = [PFQuery queryWithClassName:#"Event"];
[query whereKey:#"objectId" containedIn:_inviteList];
but I need to access _inviteList.objectId which is not possible!
I tried to use innerQuerry or relation query. but as I just started learning parse I am not able to implement this.
PFUser *friendPointer = [PFUser currentUser];
PFQuery *query2 = [PFQuery queryWithClassName:#"Event"];
[query2 whereKey:friendPointer containedIn:_inviteList];
return query2;
This also did not work for me.
PFQuery *innerQuery = [PFQuery queryWithClassName:#"Invite"];
[innerQuery whereKey:#"invitedUser" equalTo:[PFUser currentUser]];
query = [PFQuery queryWithClassName:#"Event"];
[query whereKey:#"user" matchesQuery:innerQuery];
return query;
I appreciate if anyone can help me to write this query or re-design my table in order to have access to this query.
Pleaser try this code and give me review
PFUser *user = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"Invite"];
[query whereKey:#"invitedUser" equalTo:user];
[query includeKey:#"invitedUser"];
[query includeKey:#"eventId"];
[query orderByDescending:#"updatedAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
for (PFObject *underobject in [objects reverseObjectEnumerator])
{
PFUser *user1 = underobject[#"invitedUser"];
NSLog(#"invitedUser is :%#",user1);
}
}
}];

PFQuery orSubQuery for PFQueryTableViewController not working

I had a table view working off of a compound query, and I updated Parse and now it seems to not work anymore. I'm not sure if it's the Parse update, but here's the situation:
The query is as follows (in the queryForTable method (which is called) of the PFQueryTableViewController):
self.parseClassName = #"Event";
PFQuery *attendeeQuery = [PFQuery queryWithClassName:self.parseClassName];
PFQuery *organizerQuery = [PFQuery queryWithClassName:self.parseClassName];
[attendeeQuery whereKey:#"attendees" containsAllObjectsInArray:[NSArray arrayWithObjects:[PFUser currentUser], nil]];
[organizerQuery whereKey:#"organizer" equalTo:[PFUser currentUser]];
PFQuery *query = [PFQuery orQueryWithSubqueries:#[organizerQuery, attendeeQuery]];
[query includeKey:#"organizer"];
[query whereKey:#"isVisible" equalTo:[NSNumber numberWithBool:YES]];
[query orderByAscending:#"time"];
return query;
When I run this query, objectsDidLoad never gets called and my table view hangs in the loading state. Help please!
The solution has to do with the one line I didn't include above.
I had this:
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
and it turns out in the most current Parse SDK and iOS SDK, cachePolicy is broken, so one must use kPFCachePolicyIgnoreCache to get results when using a where ContainedIn clause.
Source:
https://developers.facebook.com/bugs/717037238403238/

Parse Query Constraint Contained In Not Returning Objects

I am trying to run this query however it is returning no objects. Any help?
for (int arrayIndex=0; arrayIndex<[self.cards count]; arrayIndex++)
{
NSString *senderId = [[deck objectAtIndex:arrayIndex]objectForKey:#"SenderId"];
[list_of_sender_ids addObject:senderId];
}
PFQuery *query = [PFQuery queryWithClassName:#"User"];
[query whereKey:#"facebook_id" containedIn:list_of_sender_ids];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
A couple of things that could be going wrong right off the bat:
First of all, to query the user class, you shouldn't use
PFQuery *query = [PFQuery queryWithClassName:#"User"];
But instead,
PFQuery *query = [PFUser query];
Assuming your User class still returns PFUser objects.
Another thing to make sure is right is the #"Facebook_id" key, and confirm in Parse that this is a top level key that you can see on your Parse User objects.
Lastly, make sure #"SenderId" is also the right key on the objects in deck, since you seem not to be querying based on the same key that could cause the issue.

PFQuery to load objects stored in an array in a PFObject into a PFQueryTableViewController

I have a PFQueryTableViewController which loads Threads (PFObjects with data about a forum thread) just fine.
When a cell is pressed, a new PFQuertyTableViewController loads Responses (PFObjects with data about a user's response on the thread), but I am having trouble making sure they are Responses specific to that Thread.
I can get the entire array of responses very easily,
NSArray *responses = thread[#"responses"];
However, I have no idea how to use this with a PFQuery in a PFQueryTableViewController. Here's what I tried:
I got this idea from this forum post, but it doesn't do anything for me (self.objects is empty).
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
NSArray *threads = self.topic[#"threads"];
for (PFObject *thread in threads)
{
[thread fetchIfNeeded];
NSLog(#"Thread title: %#", thread[#"title"]);
}
[query whereKey:#"title" containedIn:threads];
return query;
}
Output:
Thread title: This is my title for my post about "Animal Rights"
2014-06-20 10:25:11.730 ThumbWar[9185:60b] Fetched: <Thread:dasLkCUo77:(null)> {
title = "This is my title for my post about \"Animal Rights\"";
user = "<PFUser:********>";
}
Use includeKey when you get Threads in your first PFQueryTableViewController. Threads will come with their Responses and you can pass these Responses to a normal UITableViewController when the cell is clicked.
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
[query includeKey:#"responses"]; //Retrieve responses of threads
[query orderByDescending:#"createdAt"]; //You may also sort Threads if you want
return query;
}

parse.com: How to compare pointer-keys with objects?

I am using the backend service parse.com for a iOS app and I have a problem with querying it properly. I need help with the method whereKey:matchesKey:inQuery;
I have this code:
//NOT WORKING
PFQuery *query1 = [PFQuery queryWithClassName:#"Object"];
PFQuery *query2 = [PFQuery queryWithClassName:#"ObjectsRelations"];
[query2 whereKey:#"user" equalTo:[PFUser currentUser]];
[query1 whereKey:#"objectId" matchesKey:#"objectPointer" inQuery:query2];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// No objects
}];
It is not working the way I want. I have tried several ways for it to compare the key "objectPointer" in class "ObjectsRelations" (which is a pointer to an instance of class Object) to the actual Object in query 1. I do not get any objects back, because the comparison does not work as I want, since the key objectId is just a string and the key objectPointer is a pointer to a Object.
When I run this code, I get the intended result, but this requires me to do two api-requests to get the actual objectId as a string!
//WORKING
PFQuery *query = [PFQuery queryWithClassName:#"Object"];
PFQuery *query2 = [PFQuery queryWithClassName:#"ObjectRelations"];
[query2 whereKey:#"user" equalTo:[PFUser currentUser]];
[query2 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
PFObject *firstObject = [((PFObject*)[objects firstObject]) objectForKey:#"objectPointer"];
[query whereKey:#"objectId" equalTo:firstObject.objectId];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
//Getting the objects correctly from the class Object!
}];
}];
How to do this with a single api-request? How to compare a instance of a Class to a pointer of a class with a query?
Something like this is what i want to do: (Pseudo Code)
[query1 where:SELF matches:#"objectPointer" inQuery:query2];
Any suggestions?
I just searched this exact same problem and there are a number of questions on the Parse forum regarding it:
Trouble with nested query using object_id
Assistance with relational query
Compare string to pointer in query with does not match key in query
The first one explains a hack to include an extra field (in this case) in your ObjectRelations class. This key/field would be a string that would be the objectId of the pointer. It would be in addition to the key/field that holds the pointer.
If you look through the questions you can see that as of now there doesn't seem to be an answer directly from Parse regarding this.
Instead of adding an additional column with type String to contain the objectID it points to, I would suggest to add a column on each object with type Pointer to point to the object itself. This would dramatically reduce the amount of the columns you have to add. The only downside is this must be done on Cloud Code.
At this question's scenario, you'll have two queries like:
//Inner query
//Library containing pointer<Deck> & pointer<User>
PFQuery * subscriptions = [PFQuery queryWithClassName:#"subscription"];
[subscriptions whereKey:#"User" equalTo:[PFUser currentUser]];
//Outer query
//Pull down a list of deckStore objects not included in the subscriptions for current user
PFQuery * decks = [PFQuery queryWithClassName:#"deckStore"];
Then instead of:
[decks whereKey:#"objectId" doesNotMatchKey:#"deckString" inQuery:subscriptions];
You can do this:
[decks whereKey:#"this" doesNotMatchKey:#"deck" inQuery:subscriptions];
Here's a sample of what the Cloud Code should be added:
Parse.Cloud.afterSave("Deck", function(request) {
var deck = request.object;
// To make sure this is the first time of "afterSave" of this object.
if (deck.createdAt.getTime() == deck.updatedAt.getTime()) {
// "this" is the column which contains the pointer of the object itself.
if (deck.get("this") == null) {
deck.set("this", deck);
deck.save();
}
}
}
I have the same problem. This is my solution:
PFQuery *query1 = [PFQuery queryWithClassName:#"tableClass"];
[query1 whereKey:#"objectId" equalTo:[(PFObject *)[object objectForKey:#"pointerField"] objectId]];
PFObject *obj1 = [query1 getObjectWithId:[(PFObject *)[object objectForKey:#"pointerField"] objectId]];
NSString *pointerName = [obj1 objectForKey:#"name"];

Resources