Получите отсортированные документы Firestore при денормализации данных - PullRequest
1 голос
/ 25 мая 2020

Я использую Firestore для своего приложения, в котором пользователи могут публиковать sh сообщений, хранящихся в коллекции сообщений :

posts
    {postID}
        content = ...
        attachementUrl = ...
        authorID = {userID}

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

user_timelines
            {userID}
                  posts
                      {documentID}
                              postID = {postID}
                              addedDate = ...

Поскольку данные денормализованы, если я хочу выполнить итерацию по временной шкале пользователя, мне нужно выполнить дополнительный (внутренний) запрос, чтобы получить полный объект Post через его {postID}, например:

    db.collection("user_timelines").document(userID).collection("posts")
    .orderBy("addedDate", "desc").limit(100).getDocuments() { (querySnap, _) in
        for queryDoc in querySnap.documents {
            let postID = queryDoc.data()["postID"] as! String
            db.collection("posts").document("postID").getDocument() { (snap, _) in
                if let postDoc = snap {
                    let post = Post(document: postDoc)
                    posts.append(post)
                } 
            }
        }
    }

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

Если бы у меня были все полные объекты Post в коллекциях временной шкалы, проблем бы не было, и .orderBy("addedDate", "desc").limit(100) работал бы просто Хорошо, сохраняя сортировку сообщений, но если я денормализирую, я не могу найти правильное решение.

Как я могу выполнить итерацию по временной шкале пользователя и убедиться, что все объекты Post отсортированы с помощью addDate, даже если денормализация данных?

Я думал о создании словаря сопоставления postID / addedDate при чтении идентификаторов postID, а затем сортировать сообщение в конце, используя этот словарь, но я думаю, что должно быть лучшее решение для этого?

Я ожидал, что это будет обычная проблема при денормализации данных, но, к сожалению, я не смог найти никаких результатов. Может, здесь что-то не хватает.

Спасибо за помощь!

1 Ответ

1 голос
/ 25 мая 2020

Что вы можете сделать, так это перечислить l oop, в котором вы выполняете внутренний запрос, который просто нумерует каждую итерацию. Оттуда вы можете расширить модель Post, включив это значение n, а затем отсортировать массив по n, когда вы закончите.

db.collection("user_timelines").document(userID).collection("posts").orderBy("addedDate", "desc").limit(100).getDocuments() { (querySnap, _) in
    for (n, queryDoc) in querySnap.documents.enumerated() {
        let postID = queryDoc.data()["postID"] as! String
        db.collection("posts").document("postID").getDocument() { (snap, _) in
            if let postDoc = snap {
                let post = Post(document: postDoc, n: n)
                posts.append(post)
            }
        }
    }
    posts.sort(by: { $0.n < $1.n })
}

Пример выше фактически не будет работать потому что l oop является асинхронным, что означает, что массив будет отсортирован до завершения всех загрузок. Для этого рассмотрите возможность использования диспетчерской группы для координации этой задачи.

db.collection("user_timelines").document(userID).collection("posts").orderBy("addedDate", "desc").limit(100).getDocuments() { (querySnap, _) in
    let dispatch = DispatchGroup()
    for (n, queryDoc) in querySnap.documents.enumerated() {
        dispatch.enter() // enter on each iteration
        let postID = queryDoc.data()["postID"] as! String
        db.collection("posts").document("postID").getDocument() { (snap, _) in
            if let postDoc = snap {
                let post = Post(document: postDoc, n: n)
                posts.append(post)
            }
            dispatch.leave() // leave no matter success or failure
        }
    }
    dispatch.notify(queue: .main) { // completion
        posts.sort(by: { $0.n < $1.n })
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...