Лучший способ получить дочерние и родительские объекты с Parse Server в iOS - PullRequest
0 голосов
/ 04 февраля 2019

Я пробую «Пример блогового приложения» на Parse Server для iOS и не могу понять, каков умный способ получить все дочерние объекты другого класса (вместе с родительскими объектами).

«Пример блогового приложения» (которое создается автоматически при создании новой учетной записи) содержит классы Comment и Post.Класс Comment содержит отношение к классу Post, как показано ниже (из панели инструментов), но в противоположном направлении отношения нет.

enter image description here

Теперь я хочу получить все сообщения и все комментарии, относящиеся к каждому сообщению .Код ниже делает это, но я предполагаю, что должен быть более разумный способ ...?Если вы знаете, как, пожалуйста, поделитесь.Заранее спасибо!

- (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);
        }
    }];
}

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Одна проблема, которую я вижу с вашим запросом, состоит в том, что есть вероятность, что он не будет получать все сообщения в базе данных.Если сообщение имеет 0 комментариев, ни один из объектов Comment не будет иметь ссылку на него, и, таким образом, вы не получите его.

Следовательно, вы должны выполнить запрос к сообщению "Post" и в его завершении выполнить запросна "Комментарий".Таким образом, вы не пропустите ни одного сообщения с 0 комментариями.Когда вы сделаете это, вам не нужно будет включать ключ «post» в запросе «Комментарий».Это имеет несколько преимуществ.

Во-первых, каждое включение также является другим запросом для этого объекта.Таким образом, каждый новый объект 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);
    }
}];
}
0 голосов
/ 07 февраля 2019

Вот как я это сделал, используя 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;
    }];
}
0 голосов
/ 04 февраля 2019

Вместо использования include в вашем запросе вы должны использовать whereKey:equals: и передать объект post в качестве второго аргумента.Это отфильтрует и вернет только те объекты комментариев, которые содержат эту запись в качестве значения для post

...