I am having two queries one is friendsrequestQuery and other is user query i want to add all the data of friendrequestQuery details into user query while fetching data from the user Query.
NSPredicate *predicate12=[NSPredicate predicateWithFormat:#"((UserFriendId == %# )AND (UserId!=%#)) OR ((UserFriendId != %# )AND (UserId==%#)) ",#"Nwk44aeSrz",#"Nwk44aeSrz",#"Nwk44aeSrz",#"Nwk44aeSrz"];
PFQuery *innerQuery = [PFQuery queryWithClassName:#"FriendsDetails" predicate:predicate12];
[innerQuery whereKey:#"BlockStatus" equalTo:#"No"];
PFQuery * userQuery = [PFUser query];
[userQuery whereKey:#"objectId" matchesKey:#"UserFriendId" inQuery:innerQuery];
[userQuery whereKey:#"objectId" matchesKey:#"UserId" inQuery:innerQuery];
[userQuery whereKey:#"objectId" notEqualTo:#"Nwk44aeSrz"];
I wil explain the thing what i need exactly is, in innerquery table i am having 10 columns but i need the data of these particular coloum data converstionid,lastmessage,lastdate while reterving the data of users query.
Now i am getting the details of userquery but not the details of innerquery,so i need the details of Innerquerydetails .
Please help me .
I think you'd be better off storing pointers as opposed to Id's, this way you can include that data as well.
I will not use predicates, I realize your query is cleaner with predicates, but I think the logic is easier to see with this. You can convert it back to predicate for yourself.
// get your user
PFUser * userForQuery; // set up your user for the query, if it's current user, = [PFUser currentUser];
// first part of predicate
PFQuery * innerQueryA = [PFQuery queryWithClassName:#"FriendsDetails"];
[innerQueryA whereKey:#"UserFriend" equalTo:userForQuery]; // from #"UserFriendId"
[innerQueryA whereKey:#"User" notEqualTo:userForQuery]; // from #"UserId"
// second part of predicate
PFQuery * innerQueryB = [PFQuery queryWithClassName:#"FriendsDetails"];
[innerQueryB whereKey:#"userFriend" notEqualTo:userForQuery]; // from #"UserFriendId"
[innerQueryB whereKey:#"user" equalTo:userForQuery]; // from #"UserId"
// combine
PFQuery * query = [PFQuery orQueryWithSubqueries:#[innerQueryA, innerQueryB]];
[query whereKey:#"BlockStatus" equalTo:#"No"];
// Now, as you remember, we are storing a pointer in #"User" as opposed to an id #"UserId" as you had it. Because of
// this, we will use parse's includeKey: feature.
[query includeKey:#"User"]; // tells the query to include the data associated with these keys;
NSMutableArray * usersRetrieved = [[NSMutableArray alloc]init];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// objects will contain all of your objects
for (PFObject * object in objects) {
[usersRetrieved addObject:object[#"User"]]; // all the data should be available for the #"User" object
}
// objects will contain all the #"friendDetails" objects
// usersRetrieved will contain all the #"User" objects
}
else {
}
}];
I realize this changes your data structure a little bit, but it should give you all of the data you need.
Related
I have the following query:
PFObject *photoData = [PFObject objectWithClassName:#"Photos"];
PFRelation *relation = [photoData relationForKey:#"photo"];
PFQuery *query = [PFQuery queryWithClassName:#"People"];
query = [relation query];
[query whereKey:#"deleted" equalTo:#NO];
[query whereKey:#"createdAt" lessThan:_createdAt];
[query orderByDescending:#"createdAt"];
query.limit = 20;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
...
}
I have a database table in Parse called People. In that table, there is a bunch of data but has a relation called photo. Now, I am saving one photo (with its data) in the photo relation. In the Parse dashboard, the data is saved correctly.
How do I fetch that back? Right now I have constraints on this system (and question) that each People objects has ONLY one photo object. So I need to fetch it all back at once.
Relation is just what its literal meaning is. It does not contain any data. If you want to query the data, you need to get the PFQuery from PFRelation by query method like so:
PFRelation *relation = [photoData relationForKey:#"photo"];
PFQuery *photoQuery = [relation query];
// perform your photoQuery here
If you limit them by one object only, then you can change your photo as Pointer type instead of using Relation.
I have two classes User and Post. The User class has a userType field and I want to retrieve all of the posts from a given userType lets call them group x. In the Post class I have a pointer to the User class.
I was trying to do something like, first retrieve all user Ids for the type of user I want:
PFQuery *queryUser = [PFQuery queryWithClassName:kFTUserClassKey];
[queryUser whereKey:kFTUserTypeKey equalTo:kFTUserTypeX];
[queryUser whereKey:kFTUserLocationKey nearGeoPoint:nearGeoPoint withinMiles:miles];
[queryUser findObjectsInBackgroundWithBlock:^(NSArray *usersTypeX, NSError *error) {
if (!error) {
NSMutableArray *objectIds = [[NSMutableArray alloc] init];
// Add ambassador ids into query
for (PFObject *userX in usersTypeX) {
[objectIds addObject:[PFObject objectWithoutDataWithClassName:kFTUserClassName objectId: userX.objectId]];
}
}
}];
And then I wanted to query based on these objectIds but I am not sure how to query on this array or if this is even the correct way to do this. How can this be done?
Parse provides a matchesQuery method on query, so ...
PFQuery *innerQuery = [PFQuery queryWithClassName:#"User"];
[innerQuery whereKey:#"userType" equalTo:#"X"]; // fix with your real user type
PFQuery *query = [PFQuery queryWithClassName:#"Post"];
[query whereKey:#"user" matchesQuery:innerQuery];
[query findObjectsInBackgroundWithBlock:^(NSArray *posts, NSError *error) {
// posts are posts where post.user.userType == X
}];
Scenario = I have an app where users can send each other Messages, Comments, and Pokes that are queried to populate the current user's notificationsTableView. There are 3 queries that must take place, one for Messages, two for Comments, and three for Pokes. The code I'm using is below...
PFQuery *messageQuery = [PFQuery queryWithClassName:#"Message"];
[messageQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[messageQuery orderByDescending:#"createdAt"];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
messages = objects;
}];
PFQuery *pokeQuery = [PFQuery queryWithClassName:#"Poke"];
[pokeQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[pokeQuery orderByDescending:#"createdAt"];
[pokeQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
pokes = objects;
}];
PFQuery *commentsQuery = [PFQuery queryWithClassName:#"Comment"];
[commentsQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[commentsQuery orderByDescending:#"createdAt"];
[commentsQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
comments = objects;
}];
What is desired = To consolidate the following arrays: "messages", "pokes", and "comments" into a single array (notificationsArray) that I can sort by "createdAt" and populate my notificationsTableView with notificationsArray objectAtIndexPath:indexPath.row.
Problems I have encountered = (there are two)
(1) When I NSLog the results of any of these queries like so...
PFQuery *messageQuery = [PFQuery queryWithClassName:#"Message"];
[messageQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[messageQuery orderByDescending:#"createdAt"];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
messages = objects;
}];
NSLog(#"messages = %#", messages);
It logs "messages = (null)". I can not for the life of me figure out why it is not being set. I know there are messages because when I NSLog the "objects" Array that comes from the query it gives me what I want. It's like the contents of the query will not leave the scope of the query itself. All of the queries above do this. If I can not get the contents of the query out of that block then I can not create an array of all of the arrays to populate the notificationsTableView with, so I'm screwed. Please help.
(2) Even if I do get the results from the queries into individual arrays, I am not sure how to create an array of arrays and order them by a key. Can anyone help me with this? Please.
You are probably looking for the +orQueryWithSubqueries:(NSArray *)queries method, but I don't understand what the return value description is:
a PFQuery that is the or of the passed in PFQueries
I'm thinking this means || (or) ?
You would do it like this:
NSArray *queryArray = [NSArray arrayWithObjects:messageQuery,pokeQuery,commentsQuery,nil];
PFQuery *allQueries = [PFQuery orQueryWithSubqueries:queryArray];
[allQueries findObjects... {
As for the second error, you are right, value is not retained because when the block loses scope all of the local variables inside get destroyed in the autoreleasepool. You need to retain this by using a strong property. self.messages = objects;
(1) You are logging messages outside of the callback function, and the log comes before the callback function returned. Try to log messages into your callback, just after assigning it.
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
messages = objects;
NSLog(#"messages = %#", messages)
}];
(2) Before sorting, create a NSMutableArray and use the addObjectsFromArray: method with each retrieved array.
To sort notifications, you should use a NSSortDescriptor, which is a mechanism that describes how to sort an array according to the format of contained objects. Here's an example that could match your needs:
NSSortDescriptor *createdAtDescriptor = [[NSSortDescriptor alloc] initWithKey:#"createdAt" ascending:YES];
notificationsArray = [messages sortedArrayUsingDescriptors:#[createdAtDescriptor]];
Hope this help!
EDIT: you can embed your temporary NSMutableArray into an autorelease pool to avoid useless memory leaks, so that the dedicated memory is freed just after you proceed to display.
EDIT: you can use orQueryWithSubqueries Parse method to merge several requests into a single one. It's not annoying in your case cause you're sorting PFObject according to their createdAt key, which is common to every PFObject. In any case, you will have to check PFObject types to display them according to their type. Please see full documentation here. Does not work for queries returning several kind of objects!
I'm querying relation data on parse and I would like the objects to come back ordered by the date they were created. I've had this method work before but haven't been able to get an ordered query using relational data. The query return is in a random order. Thanks in advance! Here's my code:
PFQuery *postQuery = [PFQuery queryWithClassName:#"Post"];
[roomQuery whereKey:#"name" equalTo:self.postName];
NSError *error;
//done on main thread to have data for next query
NSArray *results = [postQuery findObjects:&error];
PFObject *post;
if ([results count]) {
post = [results objectAtIndex:0];
NSLog(#"results were found");
} else {
NSLog(#"results were not found");
}
PFRelation *commentsRelation = [#"Comments"];
[commentsRelation.query orderByAscending:#"createdAt"];
[commentsRelation.query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error Fetching Comments: %#", error);
} else {
NSArray *comments = objects;
}
I'm a little confused by your code,
you create a "postQuery", and call it, but never use any of its data.
There's also a roomQuery that never seems to have been allocated, or used.
You're querying a specific post by its name. Are you controlling its name? If not, you should use id's
what is PFRelation commentsRelation = [#"Comments"];
Probably because it's just a snippet, this stuff is dealt with elsewhere; however, for my answer, I'm assuming that your "comments" field is an array of "Comment" class objects.
Option 1:
PFQuery * postQuery = [PFQuery queryWithClassName:#"Post"];
[postQuery whereKey:#"name" equalTo:self.postName];
// again, possibly an id field would be more reliable
// [postQuery whereKey:#"objectId" equalTo:self.postId];
[postQuery includeKey:#"Comments"];
PFObject * post = [postQuery getFirstObject];// no need to download all if you just want object at [0]
// this will contain your post and all of it's comments with only one api call
// unfortunately, it's not sorted, so you would have to run a sort.
NSArray * comments = [post[#"Comments"] sortedArrayUsingComparator: ^(id obj1, id obj2) {
return [obj1[#"createdAt" compare: obj2[#"createdAt"];
}];
Option 2:
Perhaps a better option is to rework your data structure and instead of associating the comments to the post, you could associate the post to the comments (as in the parse docs)
PFQuery * postQuery = [PFQuery queryWithClassName:#"Post"];
[postQuery whereKey:#"name" equalTo:self.postName];
// again, possibly an id field would be more reliable
// [postQuery whereKey:#"objectId" equalTo:self.postId];
PFQuery * commentQuery = [PFQuery queryWithClassName:#"Comment"];
[commentsQuery whereKey:#"parent" matchesQuery:postQuery]; // when creating a comment, set your post as its parent
[commentsQuery addOrderDescending:#"createdAt"]
[commentQuery findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {
// comments now contains the comments for myPost
}];
Both of the above solutions avoid making extra unnecessary api calls (parse charges based on calls after all!).
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"];