I'm using the following query to get some data from a Parse.com class.
What I would like to do is extract the Rating object from the NSArray rateObjects. How would I go about doing this?
thanks for any help
PFQuery *rateQuery = [PFQuery queryWithClassName:#"Rating"];
[rateQuery whereKey:#"photo" equalTo:self.photo];
[rateQuery includeKey:#"photo"];
rateQuery.cachePolicy = kPFCachePolicyNetworkElseCache;
rateQuery.limit = 20;
[rateQuery findObjectsInBackgroundWithBlock:^(NSArray *rateObjects, NSError *error)
{
if( !error )
{
NSLog(#"rateObject %#", rateObjects);
}
}
];
Here's the NSLog output:
rateObject (
"<Rating:w9ENTO29mA:(null)> {\n ACL = \"<PFACL: 0x1e0a5380>\";\n Rating = 4;\n fromUser = \"<PFUser:uV2xu0c3ec>\";\n photo = \"<Photo:Rv4qqrHUPr>\";\n toUser = \"<PFUser:uV2xu0c3ec>\";\n user = \"<PFUser:uV2xu0c3ec>\";\n}",
"<Rating:t3pjtehYR0:(null)> {\n ACL = \"<PFACL: 0x1e0f9f90>\";\n Rating = 5;\n fromUser = \"<PFUser:uV2xu0c3ec>\";\n photo = \"<Photo:Rv4qqrHUPr>\";\n toUser = \"<PFUser:uV2xu0c3ec>\";\n user = \"<PFUser:uV2xu0c3ec>\";\n}"
)
Your NSArray will contain PFObjects, which you can treat in a similar way to a dictionary. In the query you ran above you received two rating objects back. If that's not what you wanted (you only wanted a single object) you may want to revisit how you're querying your data.
Assuming your Rating class in Parse contains a key called Rating you would access it like this:
[rateObject objectForKey:#"Rating"]
You can also use the new modern literal syntax if you like - rateObject[#"rating"]
You'll need to iterate through your array to view all the rating objects that have been returned, so you'll probably end up with something like this:
for (id item in rateObjects) {
int ratingVal = [[item objectForKey:#"Rating"] intValue];
NSLog(#"Rating: %d", ratingVal);
}
You may find Parse's iOS documentation helpful - and if you're not sure what the code above actually does, you may want to review arrays and how they work in Objective-C.
Try to use this:
[rateQuery findObjectsInBackgroundWithBlock:^(NSArray *rateObjects, NSError *error)
{
if( !error )
{
NSMutableArray *data = [[NSMutableArray alloc]init];
[data addObjectsFromArray:rateObjects];
NSArray *rating_data = [data valueForKey:#"Rating"];
NSLog(#"%#",[rating_data objectAtIndex:0]);
}
}
];
I hope this will help you.
Related
I'm trying out the "Sample Blog App" on Parse Server for iOS and cannot figure out what is the smartes way to fetch all child objects of another class (together with the parent objects).
The "Sample Blog App" (which creates automatically when you create a new account) contains the classes Comment and Post. The Comment class contains a relation to the Post class as shown below (from the dashboard), but there is no relation in the opposite direction.
Now, I want to fetch all posts and all the comments related to each post. The code below does that, but I'm assuming there must be a smarter way...? If you know how, please share. Thanks in advance!
- (void)fetchPosts {
NSString *commentsKey = #"comments";
NSString *postKey = #"post";
PFQuery *query = [PFQuery queryWithClassName:#"Comment"];
[query includeKey:postKey];
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (error == nil) {
NSMutableArray *array = [[NSMutableArray alloc]init];
for (PFObject *comment in objects) {
PFObject *post = [comment objectForKey:postKey];
NSDictionary *existingPostDict = [[array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K = %#", #"post.objectId", post.objectId]] firstObject];
if (existingPostDict) {
// update comments
NSArray *comments = [[existingPostDict objectForKey:commentsKey] arrayByAddingObject:comment];
// create new dictionary and replace the old one
NSDictionary *newPostDict = [[NSDictionary alloc]initWithObjectsAndKeys:[existingPostDict objectForKey:postKey], postKey, comments, commentsKey, nil];
[array replaceObjectAtIndex:[array indexOfObject:existingPostDict] withObject:newPostDict];
}
else {
// first post, create a new dict
NSDictionary *newPostDict = [[NSDictionary alloc]initWithObjectsAndKeys:post, postKey, #[comment], commentsKey, nil];
[array addObject:newPostDict];
}
}
self.posts = array; // assuming: #property (nonatomic, strong) NSArray *posts;
}
else {
NSLog(#"Error fetching posts: %#", error.localizedDescription);
}
}];
}
Instead of using include on your query you should use whereKey:equals: and pass the post object as the second argument. This will filter and return only the comment objects that contain that have that post as their value for post
One problem I see with your query is that there is a possibility this will not fetch every post in the database. If a post has 0 comments, none of the Comment objects will have a reference to it and thus you will not receive it.
Therefore you should actually do a query on "Post" and in its completion do a query on "Comment". This way you will not miss any posts with 0 comments. When you do this, you will not need to include the "post" key in the Comment query. This has multiple benefits.
First, each include is also another query for that object. So each new Comment object will create another query in the backend. You will get rid of this automatically.
Second, for a "Post" with multiple comments, you will be querying for the same post multiple times and that same post will be returned multiple times which consumes unnecessary bandwidth.
After getting Posts and Comments separately just combine them.
Apart from that I would do the combining like so which I find more readable but that is just personal preference.
- (void)fetchPosts {
NSString *commentsKey = #"comments";
NSString *postKey = #"post";
PFQuery *query = [PFQuery queryWithClassName:#"Comment"];
[query includeKey:postKey];
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (error == nil) {
NSMutableArray *array = [[NSMutableArray alloc]init];
NSMutableDictionary *d = [NSMutableDictionary dictionary];
for (PFObject *comment in objects) {
PFObject *post = [comment objectForKey:postKey];
if (d[post.objectId]) {
[d[post.objectId][commentsKey] addObject:comment];
}
else{
d[post.objectId] = [NSMutableDictionary dictionary];
d[post.objectId][postKey]=post;
d[post.objectId][commentsKey] = [NSMutableArray arrayWithObject:comment];
}
}
for (NSString *key in [d allKeys]) {
[array addObject:d[key]];
}
self.posts = array; // assuming: #property (nonatomic, strong) NSArray *posts;
}
else {
NSLog(#"Error fetching posts: %#", error.localizedDescription);
}
}];
}
This is how I did it, using findObjectsInBackground together with continueWithSuccessBlock: methods (for better error handling one can choose continueWithBlock: instead):
- (void)fetchPosts {
/**
create "post" and "comment" queries and use a BFTask-method from
Bolts.framework to chain downloading tasks together (bundled with Parse SDK)
*/
NSMutableArray *posts = [NSMutableArray new];
PFQuery *postQuery = [PFQuery queryWithClassName:#"Post"];
[[[postQuery findObjectsInBackground] continueWithSuccessBlock:^id(BFTask * task) {
[posts addObjectsFromArray:task.result];
PFQuery *commentsQuery = [PFQuery queryWithClassName:#"Comment"];
return [commentsQuery findObjectsInBackground];
}] continueWithSuccessBlock:^id(BFTask * task) {
/**
loop through posts and filter out comments with the same objectId in post,
then create a dictionary with post and related comments. done! :)
*/
NSMutableArray *postsAndComments = [NSMutableArray new];
for (PFObject *post in posts) {
NSArray *comments = [task.result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K == %#", #"post.objectId", post.objectId]];
[postsAndComments addObject:#{#"post":post, #"comments":comments}];
}
/**
note: BFTask-blocks not running in main thread!
*/
dispatch_async(dispatch_get_main_queue(), ^{
self.posts = postsAndComments; // assuming: #property (nonatomic, strong) NSArray *posts;
});
return nil;
}];
}
I've been using Parse.com for two months, but this is the first time I get a stupid error which I can't figure out.
I've been working in an app for iOS, but in the beginning I've been working with my own user. Now I registered other users and I want to fetch them from the server.
Well, I add one object in the table Changes, where I have a user property which is a Pointer<User> (it's not _User, but User, it's custom, just an object). Well, when I try to fetch all the rows I have, the one that I have with my user are ok:
so in my debug console is like :
but when I fetch other users:
my debug console is:
so there's not any variable!!!! :(
This is my code:
PFQuery *closestChanges = [PFQuery queryWithClassName:#"Changes"];
[closestChanges whereKey:#"coordinates" nearGeoPoint:geoPoint withinKilometers:0.5f];
[closestChanges findObjectsInBackgroundWithBlock:^(NSArray *changes, NSError *error) {
arrayChanges0 = [[NSMutableArray alloc] init];
arrayChanges1 = [[NSMutableArray alloc] init];
if (changes == nil && changes.count == 0) {
[_tableView reloadData];
return;
}
for (int i = 0; i < changes.count; i++) {
PFObject *currentChange = [changes objectAtIndex:i];
PFObject *user = [currentChange valueForKey:#"user"]; // here my user is null when it's other users.
PFObject *changeToStore = [PFObject objectWithClassName:#"Changes"];
[changeToStore setValue:currentChange[#"changetype"] forKey:#"type"];
[changeToStore setValue:currentChange[#"quantity"] forKey:#"quantity"];
[changeToStore setValue:currentChange[#"date"] forKey:#"enddata"];
[changeToStore setValue:user forKey:#"user"];
if ([currentChange[#"changetype"] intValue] == 0)
[arrayChanges0 addObject:changeToStore];
else
[arrayChanges1 addObject:changeToStore];
}
[_tableView reloadData];
}];
Is there anything wrong I'm doing by adding new users???
Thank you very much in advance.
When you fetch a pointer type from a table, you will only get back the metadata which is objectId. You need to call - (instancetype)includeKey:(NSString *)key in order to get all the data back from Changes table. If you query directly from User table, you will get all the data. But in this case, you User object is a subdocument from Changes objects.
Add this line before performing querying:
[closestChanges includeKey:#"user"]
I am using parse.com to get the data like given below. I already created the data base using sqlite manager.
- (IBAction)button:(id)sender {
PFQuery *postQuery = [PFQuery queryWithClassName:#"movie"];
//movie is the class name in the parse.com in that two columns store the data
[postQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//Save results and update the table
self.postArray = objects;
NSLog(#"array....%#",self.postArray);
// [spinner startAnimating];
[self.myTable reloadData];
}
}];
}
- (void)getTheData:(id)sender {
//it is sqlite query class
model=[[DataModel alloc]init];
//here insertQuery method to send the columns class object(buk).
[model insertInformIntoDB:buk];
PFObject *post = [self.postArray objectAtIndex:indexPath.row];
NSLog(#"posttttt......%#",post);
//here parse.com column name to send the data into sqlite Columns
buk.name=[post objectForKey:#"name"];
buk.Hero=[post objectForKey:#"Hero"];
}
I got the output like this:
//this is overall movie class
array....(
"<movie:EHx3UonJmw:(null)> {\n Hero = Mahesh;\n name = pokiri;\n num = 222;\n}",
"<movie:zekgTzIsLs:(null)> {\n Hero = pawan;\n name = jhoni;\n num = 412;\n}",
"<movie:0z3ZkI4lvB:(null)> {\n Hero = Prabhas;\n name = darling;\n num = 312;\n}"
)
posttttt......<movie:EHx3UonJmw:(null)> {
Hero = Mahesh;
name = pokiri;
num = 222;
}
Error:-
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSMutableString stringWithUTF8String:]: NULL cString'
but here geting null values in buk.name and Hero....
You question is so confusing but still I would love to show what might be wrong,
[model insertInformIntoDB:buk]; should be at the end of the method where you set the properties of the buk variable
-(void)getTheData:(id)sender{
//it is sqlite query class
model=[[DataModel alloc]init];
//here insertQuery method to send the columns class object(buk).
//inserting the buk without setting the values, so move this statement at the end
//[model insertInformIntoDB:buk];
PFObject *post = [self.postArray objectAtIndex:indexPath.row];
NSLog(#"posttttt......%#",post);
//here parse.com column name to send the data into sqlite Columns
buk.name=[post objectForKey:#"name"];
buk.Hero=[post objectForKey:#"Hero"];
//save the buk
[model insertInformIntoDB:buk];
}
My PFQuery returns the following description.I am trying to fetch the objectId of the class
YouQuestions.For eg: in the below description Ovx3B1TnaC is the objectId for the first index of quesAray. But I have no idea on how to fetch it.
Printing description of quesArray:
<__NSArrayM 0xe1198f0>(
<YouQuestions:OVx3BlTnaC:(null)> {
askedUser = "<PFUser:XGvZsNyg9p>";
attachedImage = "<PFFile: 0xb4c9d20>";
category = Business;
geoLocation = "<PFGeoPoint: 0xb4c9ea0>";
question = "Who is kaka?";
thumbImage = "<PFFile: 0xb4c9dd0>";
},
This is how I did but returned nil
PFQuery *fetchTimeLine = [PFQuery queryWithClassName:#"YouQuestions"];
[fetchTimeLine whereKeyExists:#"objectId"];
[fetchTimeLine findObjectsInBackgroundWithBlock:^(NSArray *quesArray, NSError *error)
{
for (int i =0; i<quesArray.count; i++)
{
PFObject *obj = [quesArray[i] objectForKey:#"objectId"];
[searchobjectIDsArray addObject:obj.objectId];
}
}];
EDIT:
I fixed it like this
for (PFObject *object in quesArray) {
NSLog(#"%#", object.objectId);
}
to get the array of ids:
NSArray *oids = [quesArray valueForKeyPath:#"objectId"];
I'm using parse.com in an iOS app to store data to the parse cloud service. I'm having trouble with a query of nested objects. I have the following data model:
Class "Game"
contains "winners"
"winners" is an array of NSDictionary, each item in the dictionary is a mapping of 1 Player to N Powers
playerPowers value is an array of PFObjects (powers only have a name currently) for key:objectId of a player (PFObject)
For each winner, I add to "winners" (there can be multiple winners) an NSDictionary object, like so:
NSDictionary * winnerWithPowers = [NSDictionary dictionaryWithObject:tempPowers
forKey:[aWinnerPFObject objectId]];
[newGame addObject:winnerWithPowers forKey:#"winners"];
For each item in the dictionary, the key is an existing objectId of a player and the value is an array of PFObjects (powers) also on the server. When i query for the "winners" i'd like to retrieve all the data populated, all winners and their respective power PFObjects with all their data. When i query for the "winners" the details of each power PFObject is incomplete (value for key:name is null). following is the query, then the code that prints results, followed by output of a dictionary containing two winners:
// In viewWillAppear:
PFQuery * gamesQuery = [PFQuery queryWithClassName:#"Game"];
[gamesQuery orderByDescending:#"createdAt"];
[gamesQuery findObjectsInBackgroundWithBlock:^(NSArray * theGames, NSError * error) {
if (error) {
NSLog(#"ERROR: There was an error with the Query for Games!");
} else {
_gamesPF = [[NSMutableArray alloc] initWithArray:theGames];
[_tableView reloadData];
}
}];
// in the tableview cellForRowAtIndexPath: method (it's my own TableViewController)
NSArray * testArray = [[_gamesPF objectAtIndex:row] objectForKey:#"winners"];
if ([testArray count] > 0) {
// print contents of first dictionary winners entry
NSLog(#"TestDictfromPF %#", [testArray objectAtIndex:0]);
}
Log:
2013-01-18 09:42:26.430 GamesTourney[20972:19d03] TestDictfromPF {
jchtlqsuIY = (
"<Power:OlJfby1iuz:(null)> {\n}", // problem is {\n}. Data exists on server but not in local structure after query
"<Power:eQkMUThGOh:(null)> {\n}" // ditto
);
}
When you retrieve a PFObject (Game) that is related to other PFObjects (an array of Powers), the value of those Powers are not retrieved. You will have to fetch all the values of those Powers in subsequent fetch requests.
From the Parse documentation:
By default, when fetching an object, related PFObjects are not
fetched. These objects' values cannot be retrieved until they have
been fetched like so:
PFObject *post = [fetchedComment objectForKey:#"parent"];
[post fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
NSString *title = [post objectForKey:#"title"];
}];
Clarification on Fetch vs Find:
Fetches are called on PFObjects (docs) whereas Finds are used in PFQueries (docs).
Fetches require PFObjects as input, and don't return anything. Fetches simply update the values on PFObjects you've already retrieved from Parse. Finds, on the other hand, will retrieve PFObjects from Parse.
Since you have an array of Powers (which are PFObjects), use the following to retrieve all the values from Parse:
[PFObject fetchAllIfNeeded:(NSArray *)myPowers];
or fetchAllIfNeededInBackground: if you want it to be asynchronous.
PFQuery *query = [PFQuery queryWithClassName:#"Cars"];
[query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {
for (PFObject *comment in comments)
{
PFObject *post = [comment objectForKey:#"name"];
NSLog(#"%#",post);