我正在尝试在Parse Server上针对iOS的“示例博客应用程序”,无法弄清楚什么是获取另一个类的所有子对象(连同父对象)的聪明方法。
“示例博客应用程序”(在创建新帐户时自动创建)包含类Comment
和Post
。注释类包含与Post类的关系,如下所示(从仪表板显示),但是没有相反的关系。
现在,我想获取所有帖子以及与每个帖子相关的所有评论。下面的代码可以做到这一点,但是我假设必须有一种更聪明的方法...?如果您知道如何,请分享。预先感谢!
- (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);
}
}];
}
答案 0 :(得分:0)
您应该使用include
而不是在查询中使用whereKey:equals:
并将post对象作为第二个参数传递。这将过滤并仅返回包含该帖子作为post
答案 1 :(得分:0)
我在查询中看到的一个问题是,这可能不会获取数据库中的每个帖子。如果帖子的评论为0,则Comment对象都不会引用它,因此您不会收到它。
因此,您实际上应该对“ Post”进行查询,并在完成时对“ Comment”进行查询。这样,您将不会错过任何带有0条评论的帖子。当您这样做时,您将不需要在Comment查询中包括“ post”键。这有很多好处。
首先,每个include也是对该对象的另一个查询。因此,每个新的Comment对象将在后端创建另一个查询。您将自动摆脱它。
第二,对于带有多个注释的“帖子”,您将多次查询同一帖子,并且同一帖子将被多次返回,这会浪费不必要的带宽。
分别获取帖子和评论后,只需将它们组合即可。
除此之外,我会像这样进行合并,我发现它更具可读性,但这只是个人喜好。
- (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);
}
}];
}
答案 2 :(得分:0)
这是我的方法,结合使用findObjectsInBackground
和continueWithSuccessBlock:
方法(为了更好地处理错误,可以选择continueWithBlock:
)
- (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;
}];
}