遍历文档 uid 列表并在 Firestore 中创建侦听器

Posted

技术标签:

【中文标题】遍历文档 uid 列表并在 Firestore 中创建侦听器【英文标题】:Iterate through list of document uids and create listeners in Firestore 【发布时间】:2020-12-27 05:20:33 【问题描述】:

在我的 Vuex 商店中,我有一个操作,它从当前用户的 Firestore UserDataCollection 文档中获取关注用户的 uid 列表,遍历它们,并为要在 UI 上显示的每个文档生成数据。使用 .get() 可以正常工作,但我正在尝试将其转换为 .onSnapshot(),以便获得实时更新。

我尝试使用 .onSnapshot() 完全不成功,因为我在网上或 Firebase 文档中找不到任何关于如何在通过 uid 数组映射后实现此功能的参考。

我尝试删除承诺,因为 onSnapshot 似乎不适用于承诺,并将 .get() 替换为 .onSnapshot(),但这没有用。

根据下面的代码,有人知道实现 Firestore .onSnapshot() 侦听器的正确方法吗?

getCircle(state, commit) 
      const circle = state.userProfile.circle
      let promises = circle.map(u => userDataCollection.doc(u).get())
      
        return Promise.all(promises)

        .then(querySnapShot => 
          let circleData = []
          if (querySnapShot.empty) 
            console.log("empty")
           else 
            querySnapShot.forEach(doc => 
              let item = doc.data()
              circleData.push(item)
             
            )
          
          commit('setUserCircle', circleData)
        )
   ,

根据回复修改

我在 forEach 中添加了 .onSnapshot,如下面的代码所示。在 vue devtools 中,它显示了我的 Vuex 存储中正确数量的数据条目,但是它们都是未定义的。

getCircle(state, commit) 
  const circle = state.userProfile.circle
  let promises = circle.map(u => userDataCollection.doc(u).get())
  
    return Promise.all(promises)

    .then(querySnapShot => 
      let circleData = []
      if (querySnapShot.empty) 
        console.log("empty")
       else 
        querySnapShot.forEach(x => 
          let itemId = x.data().uid
          userDataCollection.doc(itemId)
            .onSnapshot((doc) => 
              let item = doc.data()
              console.log(doc.data())
              circleData.push(item)
          )   
          
        )
      
      commit('setUserCircle', circleData)
    )

,

【问题讨论】:

如果你想监听 X 个单个文档的变化,你必须建立 X 个监听器,每个文档一个。解决这个问题没有简单的方法。不过,您可以在它们之间共享回调。从你的问题中不清楚你在哪里遇到这个问题。 所以你是说在forEach中,我需要实现.onSnapshot()? 听起来不错。 根据您的回答更新了问题。似乎数据正在被处理,但返回为未定义。但是,至少 undefined 的条目数与应返回的记录数匹配。 如果您在实施过程中遇到问题,该问题应指出具体哪些方面没有按您预期的方式工作,以及您是如何观察的。 “返回未定义”不是很具体。 【参考方案1】:

在呈现的代码中,commitonSnapshot 回调之前只运行一次。我尝试创建显示机制的示例(我假设 circle 数组已正确分配,并且我有 3 项硬编码):

let promises = circle.map(u => userDataCollection.doc(u).get())

Promise.all(promises)
.then( querySnapShot =>  
    var circleData = []
     querySnapShot.forEach( x  => 
        let itemId = x.data().uid
        userDataCollection.doc(itemId).onSnapshot(doc => 
            let item = doc.data()
            circleData.push(item)
            console.log("inside snapshot: ",circleData.length)
        )
    )
    console.log("outside foreach: ",circleData.length)
)

如果您运行此代码,您应该会在控制台中看到类似这样的内容(我已经在节点中运行过):

outside foreach:  0
inside snapshot:  1
inside snapshot:  2
inside snapshot:  3

如果您在 Firestore 中进行任何更改,您将获得另一个控制台日志inside snapshot: 4

我对您的应用程序逻辑没有完全了解,但是我认为commit 语句应该在onSnapshot 侦听器中。但当然,根据我掌握的信息,这只是猜测。

【讨论】:

谢谢,我将提交添加到侦听器内部。但是,当我尝试在 UI 中引用数据时,数据返回为“未定义不是对象”。【参考方案2】:

感谢大家的帮助。有效的解决方案是删除 .map 和 Promise 并使用“in”查询。代码如下:

 getCircle(state, commit) 
   const circle = state.userProfile.circle

   userDataCollection.where('__name__', 'in', circle).onSnapshot(querySnapShot => 
    var circleData = []
    querySnapShot.forEach(doc => 
      let item = doc.data()
      circleData.push(item)
      commit('setUserCircle', circleData)
    )
  )
,

【讨论】:

以上是关于遍历文档 uid 列表并在 Firestore 中创建侦听器的主要内容,如果未能解决你的问题,请参考以下文章

Firestore - 云功能 - 获取删除文档的用户的 uid

如何从 Cloud Firestore 中获取数据,其中 user.uid 等于 Flutter 中的文档 ID?

对于与用户 uid 相同的文档 ID,如何从 Firestore 中仅检索一个用户的数据?

Flutter Firestore:从 Firestore 中检索数据并在 Flutter 中显示为小部件

添加新字段或更改所有 Firestore 文档的结构

无法为 Android 应用程序的特定经过身份验证的用户 (uid) 编写***集合(列表权限)的 Firestore 安全规则