【问题标题】:Get sorted Firestore documents when denormalizing data非规范化数据时获取排序的 Firestore 文档
【发布时间】:2020-05-25 12:08:07
【问题描述】:

我将 Firestore 用于我的应用,用户可以在该应用上发布帖子,存储在 posts 集合中:

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

每个用户还将有一个时间线,其中将显示他们关注的人的帖子。为此,我还保留了一个通过云函数填充的 user_timelines 集合:

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

因为数据是非规范化的,如果我想遍历用户的时间线,我需要执行额外的(内部)查询以通过其 {postID} 获取完整的 Post 对象,如下所示:

    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) 可以很好地保持帖子排序,但如果我非规范化,我似乎无法找到正确的解决方案。

我怎样才能遍历用户的时间线,并确保即使在非规范化数据时也能获得按 addedDate 排序的所有 Post 对象?

我正在考虑在读取 postID 时创建一个映射字典 postID/ addedDate,然后使用此字典在最后对 Post 进行排序,但我认为必须有更好的解决方案?

我原以为这是非规范化数据时的常见问题,但不幸的是我找不到任何结果。也许我在这里缺少一些东西。

感谢您的帮助!

【问题讨论】:

    标签: swift firebase google-cloud-firestore


    【解决方案1】:

    您可以做的是枚举执行内部查询的循环,它只是对每次迭代进行编号。从那里,您可以扩展 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 })
    }
    

    上面的例子实际上不起作用,因为循环是异步的,这意味着数组将在所有下载完成之前进行排序。为此,请考虑使用调度组来协调此任务。

    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 })
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-09
      • 1970-01-01
      • 2019-06-12
      • 2018-05-06
      • 2017-01-14
      • 2013-12-11
      • 2011-10-31
      • 1970-01-01
      相关资源
      最近更新 更多