FireStore - 如何绕过数组“不包含”查询

bhe*_*h90 5 database nosql firebase swift google-cloud-firestore

经过一些研究,很明显我不能使用 FireStore 来查询给定数组不包含的项目。有没有人对此用例有解决方法?...

用户注册后,应用程序会获取一堆卡片,每张卡片在 FireStore 中都有一个对应的“卡片”文档。用户与卡片交互后,卡片文档将用户的 uid 添加到字段数组中(例如:usersWhoHaveSeenThisCard: [userUID]),“user”文档将卡片的 uid 添加到字段数组中(例如:cardsThisUserHasSeen: [cardUID]) )。“user”文档位于“user”集合中,“card”文档位于“card”集合中。

目前,我想获取用户未与之交互的所有卡片。但是,这是有问题的,因为我只知道用户与之交互的卡片,因此 .whereField(usersWhoHaveSeenThisCard, arrayContains: currentUserUID) 将不起作用,因为我需要一个不存在的“arrayDoesNotContain”语句。

最后,用户不能拥有卡片,因此我无法在卡片文档中创建真/假布尔字段(例如:userHasSeenThisCard:false)并根据该条件进行搜索。

我能想到的唯一解决方案是在卡片文档上创建一个新的字段数组,其中包含所有没有看过卡片的用户(例如:usersWhoHaveNotSeenThisCard:[userUID]),但这意味着每个注册的用户都会必须将他们的 uid 写入 1000 多个卡文件,这会吃掉我的数据。

我可能只是不走运,但我希望更了解 NOSQL/FireStore 的人可以提供一些见解。

// If any code sample would help, please let me know and I'll update - I think this is largely conceptual as of now
Run Code Online (Sandbox Code Playgroud)

Jay*_*Jay 1

有一个公认的良好答案,但是,它没有提供问题的直接解决方案,所以这里...(这可能有帮助,也可能没有帮助,但它确实有效)

我不知道你的 Firestore 结构到底是什么,所以这是我的假设:

cards
   card_id_0
      usersWhoHaveSeenThisCard
         0: uid_0
         1: uid_1
         2: uid_2
   card_id_1
      usersWhoHaveSeenThisCard
         0: uid_2
         1: uid_3
   card_id_2
      usersWhoHaveSeenThisCard
         0: uid_1
         1: uid_3
Run Code Online (Sandbox Code Playgroud)

假设我们想知道哪些卡 uid_2 没有见过 - 在本例中是 card_id_2

func findCardsUserHasNotSeen(uidToCheck: String, completion: @escaping ( ([String]) -> Void ) ) {
    let ref = self.db.collection("cards")

    ref.getDocuments(completion: { snapshot, err in
        if let err = err {
            print(err.localizedDescription)
            return
        }

        guard let docs = snapshot?.documents else {
            print("no docs")
            return
        }
        var documentsIdsThatDoNotContainThisUser = [String]()
        for doc in docs {
            let uidArray = doc.get("usersWhoHaveSeenThisCard") as! [String]
            let x = uidArray.contains(uidToCheck)
            if x == false {
                documentsIdsThatDoNotContainThisUser.append(doc.documentID)
            }
        }
        completion(documentsIdsThatDoNotContainThisUser)
    })
}
Run Code Online (Sandbox Code Playgroud)

然后,用例是这样的

func checkUserAction() {
    let uid = "uid_2" //the user id to check
    self.findCardsUserHasNotSeen(uidToCheck: uid, completion: { result in
        if result.count == 0 {
            print("user: \(uid) has seen all cards")
            return
        }
        for docId in result {
            print("user: \(uid) has not seen: \(docId)")
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

和输出

user: uid_2 has not seen: card_id_2
Run Code Online (Sandbox Code Playgroud)

此代码遍历文档,获取存储在每个文档的 usersWhoHaveSeenThisCard 节点中的 uid 数组,并确定 uid 是否在数组中。如果没有,它会将该 documentID 添加到 DocumentsIdsThatDoNotContainThisUser 数组中。检查完所有文档后,将返回不包含用户 ID 的 documentID 数组。

知道 Firestore 的速度有多快后,我针对大型数据集运行了代码,并且结果返回得非常快,因此对于大多数用例来说,它不会造成任何类型的延迟。