Parse.com 'retweet' шаблон слишком многословный

Итак, мне было поручено реализовать в приложении (iOS, Swift) функциональность "retweet", используя Parse.

Это было задано до здесь, но это a) довольно высокий уровень и b) я получаю задание под рукой - я не обязательно прошу помощи архитектурные решения, хотя, если кажется, что я, очевидно, чего-то не хватает, я рад принять обратную связь.

В моем приложении есть ПРИЧИНЫ, которые создаются пользователем. Существует также таблица FOLLOW с пользователем TO и FROM. Поэтому для начала я просто запрашиваю таблицу CAUSES с ограничением, которое USER, который разместил, должен соответствовать объектуId пользователя TO (где текущий пользователь является пользователем FROM) в таблице FOLLOW. Более кратко:

let getFollowedUsersQuery = PFQuery(className: Constants.kParseClassFollowers)
getFollowedUsersQuery.whereKey(Constants.kParseFieldFromUser, equalTo: PFUser.currentUser()!)

let causesQuery = PFQuery(className: Constants.kParseClassCauses)
causesQuery.whereKey(Constants.kParseFieldFromUser, matchesKey: Constants.kParseFieldToUser, inQuery: getFollowedUsersQuery)
causesQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
    if let causes = objects {
        for cause in causes {
          // populate the tableview cells, etc.
        }
    }
})

Теперь у меня есть все причины от пользователей, за которыми я следую... что все довольно стандартно.

Здесь, где это становится сложно.
Каждая ПРИЧИНА также имеет отношение, называемое SUPPORTERS. Теперь мне нужно архивировать способ получить все ПРИЧИНЫ от людей, за которыми я не следую, но которые имеют в своем списке сторонников пользователя, которого я придерживаюсь.

Мне еще предстоит найти элегантное решение, хотя я приближаюсь к "грубой силе", и это настолько громоздко и многословно, что лучшая половина моего мозга программиста кричит на меня, как Сьюзан Паутер...

Здесь пример:

let retweetQuery = PFQuery(className: Constants.kParseClassCauses)
retweetQuery.orderByDescending(Constants.kParseFieldCreatedAt)
retweetQuery.whereKey(Constants.kParseFieldFromUser, notEqualTo: PFUser.currentUser()!)
retweetQuery.whereKey(Constants.kParseFieldFromUser, doesNotMatchKey: Constants.kParseFieldToUser, inQuery: getFollowedUsersQuery)
retweetQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
    if let causes = objects {
        for cause in causes {
            let supporterRelations = cause.relationForKey(Constants.kParseClassSupporters)
            let supporterQuery = supporterRelations.query()
            supporterQuery.findObjectsInBackgroundWithBlock { (supporters, error) in
                if(error == nil && supporters?.count > 0) {
                    for supporter in supporters! {
                        let user:PFUser = supporter as! PFUser
                        getFollowedUsersQuery.whereKey(Constants.kParseFieldToUser, equalTo: user)
                        getFollowedUsersQuery.whereKey(Constants.kParseFieldFromUser, equalTo: PFUser.currentUser()!)
                        getFollowedUsersQuery.findObjectsInBackgroundWithBlock({ (results, error) -> Void in
                            if(error == nil && results?.count > 0) {
                                for result in results! {
                                    // do stuff
                                }
                            }
                        })
                    }
                }
            }
        }
    }
})

Теперь это чистое безумие и невероятно расточительное (особенно учитывая, как Parse вычисляет свободный уровень), я считаю, что это может действительно сильно повлиять на мой лимит API, если оно будет перенесено на производство).

Уже выполнив два запроса, я полностью переделаю их, затем выполним другой запрос для каждой причины в отношениях SUPPORTER, затем выполните другой запрос для каждого пользователя в этом отношении, чтобы увидеть, следую ли я им... и как только я мне нужно пройти через поддерживаемые пользователем причины (из-за асинхронного возвращения запросов Parse я не чувствую, что могу просто вернуться обратно в родительские петли), которые я еще не реализовал, потому что я собираюсь бросить полотенце - должен быть лучший способ!

Я надеюсь, что здесь отсутствует стратегия...

Ответ 1

@jesses.co.tt Прошу прощения, если это слишком поздно, я определенно хочу отметить, что я отвечаю в эти месяцы после того, как его спросили, но я думаю, что это стоит ответить вообще (и, возможно, по-прежнему будет полезен для вас).

В общем, я на 100% согласен с тем, что этот тройной запрос с Parse: a) будет массово неэффективным, как он выставил счет (в старой системе) и b) с учетом этого, кажется неправильным подходом даже с самим собой -hosted Parse (который контекстуально является единственным механизмом, который можно использовать в этот момент, поскольку Parse теперь закрыт, но я думаю, что все еще возможно, когда был задан вопрос... независимо...). Есть два решения, которые я вижу, которые могут исправить это довольно чистым способом, предполагая, что эти изменения могут быть внесены в общую схему/архитектуру.

1) Первым решением является повторная схематизация набора данных и по существу "внешнего ключа" подмножества сторонников, каждый из которых User имеет в самой таблице User. Таким образом, вместо перехода от CauseSupporterUser теоретически вы сможете сделать CauseUser (где от пользователей вы получите своих сторонников по умолчанию так как это будет колонка). Чтобы сделать это в Parse, если я правильно помню, вы можете установить для столбца массив определенного типа в качестве значения, а затем иметь object ссылки (которые хорошо отображаются в панель инструментов Parse), которые являются фактическими объектами таблицы Supporter, но сохраняя этот столбец ссылок на эту таблицу в таблице User.

Пока немного работаем над стороной write, так как вам придется вручную сделать это (вручную я имею в виду написать код самостоятельно, чтобы это сделать, оно должно быть автоматизировано, но это не произойдет бесплатно с точки зрения развития). С помощью этой немного более предварительной операции write у вас будет 2 шаг read вместо 3.

2). Второе решение - использовать другой поставщик данных такого типа, если проблема с запросами. В нескольких моих проектах я использую подходы на основе сокетов для такого поиска запросов к данным и думает, что Pusher или Firebase (оба очень разных уровня "все включено", Firebase, гораздо больше похоже на "Анализ", но из Google на этот раз Pusher будет немного более базовым и "сделай сам" ).

С Firebase, например, и сокет в этот набор данных + схема, в которой сама таблица Cause имеет кэш того, что User принадлежит им (и в котором User имеет кэш своих Supporter s), этот трехэтапный поиск может эффективно быть 1 запросом с 2 параметрами (которые я думаю, идеальный сценарий). Я считаю, что это может быть достигнуто и с помощью Parse, но для первого предлагаемого решения потребуется другой этап реорганизации схемы.

Я думаю, что в комментариях рекомендуется нечто подобное этому (оба решения выше), но в гораздо более непроработанном формате. Надеюсь, это поможет первопроходцу или кому-то другому. Теоретически, теоретически, как рекомендовал кто-то, используйте PubNub как упоминалось 1 комментарий, но это могло бы просто как легко построить эту схему в БД PostgreSQL, размещенную на AWS или Heroku, и выполните те же самые механизмы, что и Parse без накладных расходов.

Кроме того, поскольку это относится к Parse, который теперь предлагается только как самоорганизованное решение с открытым исходным кодом, вот руководство по переносу на хостинг Parse на своем собственном сервере AWS: здесь