FireStore Как сделать ClientSideJoin - PullRequest
       4

FireStore Как сделать ClientSideJoin

0 голосов
/ 17 октября 2018

пользователей и сообщений находятся в отдельных ссылках.

Ниже я хочу сделать следующее.

Сначала получите сообщение от postsRef, получите соответствующего пользователя в usersRef с помощью post.ownerID, введитеоба в кортеже.Повторите это.

// 1, Get Posts
// 2, Get Post's Owner by using ownerID of the Post
// 3, Add (Post, User) to Joined Posts
// 4, Repeat 1,2,3
func getPostsByNew(onSuccess: @escaping ([(Post, User)]) -> Void) {
    postsRef.order(by: timestamp_field, descending: false).getDocuments { (snapshot, error) in
        if let _ = error { return }
        var joinedPosts: [(post: Post, user: User)] = []
        guard let documents = snapshot?.documents else { return }
        for document in documents {
            let post = Post(dict: document.data(), key: document.documentID)
            print("ownerID: ", post.ownerID)  // "user_1(ownerID)"
            API.User.getUser(userID: post.ownerID!, completion: { (user) in
            print("userID: ", user.userID)  // "user_1(userID)"
                joinedPosts.append((post: post, user: user))
            })
        }
        print(joinedPosts.count)  // 0
        onSuccess(joinedPosts)
    }
}

Для print("ownerID:", post.ownerID) и print("userID:", user.userID) в операторе for было отображено нормальное количество идентификаторов.Но почему print(joinedPosts.count) отображается как 0?

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

1 Ответ

0 голосов
/ 17 октября 2018

Редактировать: Этот вопрос предназначен для FireStore, поэтому этот ответ включает в себя ответ базы данных Firebase, а также ответ Firestore и затем полный ответ Firestore.

База данных Firebase Вопрос состоит в том, какпереберите узел сообщений и найдите пользователя, связанного с каждым сообщением, с помощью uid пользователя.

Вот, пожалуйста,

С учетом структуры

posts
  post_0
    post: "some post"
    uid: "uid_1"
  post_1
    post: "another post"
    uid: "uid_1"
users
  uid_0
    Name: "Henry"
  uid_1
    Name: "Josh"

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

let postsRef = self.ref.child("posts")
let usersRef = self.ref.child("users")
postsRef.observeSingleEvent(of: .value, with: { snapshot in
    guard let allPostsSnapshot = snapshot.children.allObjects as? [DataSnapshot] else {return}
    for childPostSnap in allPostsSnapshot {
        let uid = childPostSnap.childSnapshot(forPath: "uid").value as! String
        let post = childPostSnap.childSnapshot(forPath: "post").value as! String
        let thisUserRef = usersRef.child(uid)
        thisUserRef.observeSingleEvent(of: .value, with: { userSnap in
            let userName = userSnap.childSnapshot(forPath: "Name").value as! String
            print(post, userName)
        })
    }
})

и вывод

some post  Josh
another post  Josh

FireStore

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

func readPosts() {
   self.db.collection("posts").getDocuments() { (querySnapshot, err) in
       if let err = err {
           print("Error getting documents: \(err)")
       } else {
           for document in querySnapshot!.documents {
               let uid = document.get("uid") as! String
               let post = document.get("post") as! String
               self.printUserAndPost(withUid: uid, andPost: post)
           }
       }
   }
}

func printUserAndPost(withUid: String, andPost: String) {
   let docRef = self.db.collection("users").document(withUid)
   docRef.getDocument { (document, error) in
       if let document = document, document.exists {
           let name = document.get("name") as! String
           print(name, andPost)
       } else {
           print("doument does not exist")
       }
   }
}

и вывод

Josh Some Post
Josh Another post

Другое редактирование:

Основываясь на комментариях к исходному постеру, они хотели бы добавить объект публикации и объект пользователя и массив в виде кортежа.Поскольку у нас нет этой информации в исходном посте, я разработал довольно полное решение - см. Ниже.Второй вопрос: почему массив кортежей печатает счет 0 в исходной записи?Причина в том, что Firebase / Firestore является асинхронным и в исходном вопросе эта строка

print(joinedPosts.count)

вызывается до , когда пользователи заполняются с

API.User.getUser(userID: post.ownerID!

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

class PostClass {
    var post_id = ""
    var post_text = ""
    var owner_id = ""
    init(ownerId: String, postId: String, postText: String) {
        self.owner_id = ownerId
        self.post_id = postId
        self.post_text = postText
    }
}

class UserClass {
    var user_id = ""
    var user_name = ""
    init(userId: String, userName: String) {
        self.user_id = userId
        self.user_name = userName
    }
}

var joinedPosts = [(aUser: UserClass, aPost: PostClass)]()
var docCount = 0

func readPosts() {
    self.db.collection("posts").getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            self.docCount = querySnapshot!.documents.count

            for document in querySnapshot!.documents {
                let postId = document.documentID
                let uid = document.get("uid") as! String
                let postText = document.get("post") as! String
                let post = PostClass(ownerId: uid, postId: postId, postText: postText)
                self.addUserAndPostTupleToArray(withUid: uid, andPost: post)
            }
        }
    }
}

func addUserAndPostTupleToArray(withUid: String, andPost: PostClass) {
    let docRef = self.db.collection("users").document(withUid)
    docRef.getDocument { (document, error) in
        if let document = document, document.exists {
            let name = document.get("name") as! String
            let user = UserClass(userId: withUid, userName: name)
            let myTuple = (aUser: user, aPost: andPost)
            self.joinedPosts.append(myTuple)

            if self.joinedPosts.count == self.docCount {
                print("total posts: \(self.joinedPosts.count)")
                for myTuple in self.joinedPosts {
                   let name = myTuple.aUser.user_name
                   let postText = myTuple.aPost.post_text
                   print("User \(name) said \(postText)")
                }
            }
        } else {
            print("doument does not exist")
        }
    }
}

и вывод

total posts: 2
User Josh said Some Post
User Josh said Another post
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...