1

我正在解决一个简单的逻辑问题,但我似乎无法让事情顺利进行。让我分享一下我最有说服力的代码实验,然后我会分享一些想法。

useEffect(() => {
    firebase
        .firestore()
        .collection("someCollection")
        .orderBy("date", "desc")
        .onSnapshot(docs => {
            let documents = []
            if (canGetUpdatesFromFirestore.current) {
                docs.forEach((doc) => {
                    documents.push(doc.data())
                })

                if(documents.length > 3) {
                    documents.splice(4, 0, {questionPostId: 0})
                    documents.splice(5, 0, {questionPostId: 1})
                }
                setAllQuestions(documents)
                setUsers(documents)

            }

        })
    if (searchValue.length > 2) {
        canGetUpdatesFromFirestore.current = false;
        functions.searchForSearchVal(searchValue, "Sexuality")
            .then((result) => {
                setAllQuestions(result);
            })
    } else {
        canGetUpdatesFromFirestore.current = true
    }
}, [searchValue])

function setUsers(docs){
    let arrFinal = []
    let copyOfAllQuestions = ""
        for(let i = 0; i< docs.length; i++) {
            console.log("HERE")
            if (docs[i].postedBy) {
                docs[i].ref.get().then(userFire => {
                    copyOfAllQuestions = {
                        ...allQuestions,
                        ...{hasPremium: userFire.data().hasPremium}
                    }
                })
                arrFinal.push(copyOfAllQuestions)
            }

        }
    setAllQuestions(arrFinal)
}

让我分享一下我目前的状态以及我正在努力完成的工作。我有一个显示allQuestions。每个问题数据都有一个指向其在 firestore 中的用户文档的引用。对于每个问题,我都需要检查该用户是否 hasPremium。我应该如何以正确的方式做到这一点?目前的问题是我可以通过ref从我的Users集合中获取数据,但我必须刷新我的状态才能显示所有数据。有人可以帮我走上正确的道路/请正确思考这个问题吗?

4

1 回答 1

2

我提出的一种方法是采用数据非规范化。也就是说,不是将其他文档(用户)的引用放在问题文档中,而是将所有相关的用户信息直接放入问题文档中。

这与 SQL 数据库方法是对立的,但这没关系,因为 Firestore 是“NoSQL”。拥抱反 SQL 身份!!

本质上,在您的问题文档中,您希望在处理问题时复制应用程序中所需的任何信息,并避免通过获取其他文档来进行“连接”。您不需要将所有用户文档复制到问题文档中 - 只需将您的应用程序处理问题时所需的元素。

例如,也许在问题中您需要的只是:

question: {
    name: ...,
    type: ...,
    lastUpdated: ...,
    postedBy: {
      email: ...,
      displayName: ...,
      avatarUrl: ...,
      hasPremium: true,
    }
}

对于重复数据,您通常需要一种机制来使重复数据从其“源”保持最新。因此,您可能会考虑onUpdate()对用户文档使用 Cloud Function 触发器,并且当修改相关值(emaildisplayNameavatarUrl和/或hasPremium)时,您将遍历该用户发布的所有问题并进行相应更新。

这里的经验法则是:

  • 您的应用程序中一个屏幕/功能所需的所有数据都进入一个文档
  • NoSQL 文档存储用于频繁读取和不频繁写入的地方
  • NoSQL 数据存储(通常)没有“连接” - 所以不要设计你的应用程序来要求它们(这就是你上面的代码正在做的事情:加入问题和用户)
  • 通常你并不关心更新所有重复数据的实例(例如,如果用户今天更新了他们的 displayName,你应该更新他们 3 年前发布的问题吗?——不同的应用程序/业务需求会给出不同的答案)
于 2020-11-19T19:10:49.913 回答