Firestore - получение сообщений для учетных записей, на которые подписан пользователь

Я пытаюсь получить сообщения из списка учетных записей, на которые подписан пользователь, но не уверен, как это сделать? Я реализовал ту же структуру из этого ответ на переполнение стека, так как считаю ее разумной для того, что я пытался создать (см. Ниже).

Firestore-root
   |
   --- users (collection)
   |     |
   |     --- uid (documents)
   |          |
   |          --- name: "User Name"
   |          |
   |          --- email: "[email protected]"
   |
   --- following (collection)
   |      |
   |      --- uid (document)
   |           |
   |           --- userFollowing (collection)
   |                 |
   |                 --- uid (documents)
   |                 |
   |                 --- uid (documents)
   |
   --- posts (collection)
         |
         --- uid (documents)
              |
              --- userPosts (collection)
                    |
                    --- postId (documents)
                    |     |
                    |     --- title: "Post Title"
                    |     |
                    |     --- date: September 03, 2018 at 6:16:58 PM UTC+3
                    |
                    --- postId (documents)
                          |
                          --- title: "Post Title"
                          |
                          --- date: September 03, 2018 at 6:16:58 PM UTC+3

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

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

var userFollowingList = [User]()

db.collection("Following").document(currentUserUID).collection("userFollowing")
    .getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            completion(false)
        } else {
            for document in querySnapshot!.documents {
                print("\(document.documentID) => \(document.data())")
                userFollowingList = querySnapshot!.documents.compactMap { querySnapshot -> User? in
                    return try? querySnapshot.data(as: User.self)
                }
            }
for user in userFollowingList {
    db.collection("Posts")
        .getDocuments() { (tripQuerySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
                completion(false)
            } else {
                for document in tripQuerySnapshot!.documents {
                    print("\(document.documentID) => \(document.data())")
                    self.followingTrips = querySnapshot!.documents.compactMap { querySnapshot -> Trip? in
                        return try? querySnapshot.data(as: Trip.self)
                    }
                }
            }
        }
    }   
}

Какой самый эффективный способ добиться этого? Спасибо.

ОБНОВЛЕНИЕ 30/03/2020:

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

let userFollowingIDs = ["01","02","03"]
    
    
    for id in userFollowingIDs {
        db.collection("Trips").document(id).collection("userPosts")
            .getDocuments() { (querySnapshot, err) in
                if let err = err {
                    print("Error getting documents: \(err)")
                    completion(false)
                } else {
                    for document in querySnapshot!.documents {
                        print("\(document.documentID) => \(document.data())")
                        self.followingTripsList = querySnapshot!.documents.compactMap { querySnapshot -> Trip? in
                            return try? querySnapshot.data(as: Trip.self)
                        }
                    }
                    completion(true)
                }
            }
        }

Вопрос и проблема немного неясны. Есть узел следующий, в котором есть документы с идентификатором пользователя в качестве ключа для каждого. В нем находится список uid пользователей, за которыми они следят. Итак, если вы загрузите эту коллекцию userFollowing, вы узнаете все uid, за которыми они следуют. Есть коллекция aсообщения, организованная uid. Если вы перебираете каждый загруженный uid, вы можете загрузить соответствующие сообщения пользователей из коллекции сообщений. Есть что-то еще? Что вы делаете со всеми этими данными сразу? +1 для вашего ascii art, кстати, - сделал структуру Firestore действительно понятной.

Jay 30.03.2021 22:15

Привет, Джей. В итоге я выбрал тот подход, который вы отметили, и обновил свой пост, чтобы показать последний код. Извините за непонятность, вы правы, и это то, что я хотел сделать, я просто надеялся, что есть лучший способ, поэтому мне не нужно было сначала получать коллекцию usersFollowing. К сожалению, искусство ascii не мое, лол, я скопировал пример из связанного вопроса о переполнении стека.

user2047296 30.03.2021 22:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
49
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что это можно сделать проще. Конечно, у меня нет подробностей всей системы, однако, глядя на эту конкретную проблему, я бы добавил в каждый документ userPosts новое поле followedBy. Это поле будет массивом, в котором будут храниться все следующие идентификаторы пользователей сообщения (uid).

Теперь проверка, следит ли за конкретными сообщениями конкретный пользователь, может быть выполнена путем проверки, содержит ли этот массив followedBy этот идентификатор пользователя. Тогда можно будет использовать две функции Firestore: collectionGroup и arrayContains filter.

Тогда получить список сообщений, за которыми следует конкретный пользователь, будет очень просто, вот так:

db.collectionGroup("userPosts")
            .whereField("followedBy", arrayContains: uid)
            .getDocuments() { (snapshot, error) in
            // ...

Никаких циклов и меньше документов из Firestore. Это должно быть более эффективным с точки зрения затрат на использование.

Спасибо, vitooh, я раньше не думал об этом подходе, но определенно имеет больше смысла. Я реализовал это сейчас и работает нормально. Для всех, кто может это прочитать, вам нужно будет настроить индексы в firebase, но при первом запуске кода вам будет показана ошибка, которая дает вам ссылку для использования для создания нужного индекса.

user2047296 31.03.2021 15:09

Добро пожаловать, и да. Правда насчет индексов можно это проверить вопрос

vitooh 01.04.2021 09:34

Другие вопросы по теме

Flutter Не удалось зарегистрировать ServiceWorker для области с помощью сценария, сценарий имеет неподдерживаемый тип MIME
Как установить Ghost CMS в подкаталог хостинга firebase
Правила Firestore позволяют только владельцу документа обновлять его, а другим пользователям - обновлять определенные поля
Функции Firebase не компилируют код. Он выдает код состояния 246 при неудачной компиляции
Проблема CORS - доступ к извлечению в *** из источника *** был заблокирован политикой CORS: No 'Access-Control-Allow-Origin' - запрос PUT в Firebase
Как я могу получить определенные пользовательские данные из firestore в React?
Как каждый день делать разные номера аутентификации без редактирования кода?
Как я могу получить определенные пользовательские данные из firestore в React
Когда пользователь пытается войти в систему, он не сохраняет свои данные в хранилище, когда я нажимаю кнопку «Подтвердить местоположение», отображается следующая ошибка
Каким будет решение, если мой ключ api действителен и подходит, но студия Android все еще показывает ошибку, пожалуйста, передайте действительный ключ api во флаттере?

Похожие вопросы

Как обрабатывать JSON с нулевыми значениями с помощью Decodable
Как я могу быстро получить значения переменной ответа в другом представлении ... когда я пытаюсь получить доступ к этой переменной, она возвращает ноль ... необходимо решить эту проблему
Невозможно добавить пользовательский вид в мое приложение iOS, ios14, Swift
Как я могу убедиться, что мой пользовательский отрисовщик Xamarin.Forms iOS моей записи использует ширину элемента?
Ячейка uicollectionview выводится из границы коллекции при использовании прозрачной панели навигации
Быстрый зум камеры до 0,5x в широкоугольном объективе
Объедините предварительную выборку и кеширование результатов
Я хочу добавить вкладки, такие как android, в мое быстрое приложение для iOS
Можете ли вы использовать тестирование песочницы App Store (в частности, verifyReceipt) перед отправкой приложения или связанных IAP?
Пользовательский UIButton с setImage не активируется