我正在使用此数据模型尝试 Firestore:
{ name: string, move?: Ref<move> }
{ name: string }
我有 2 个神奇宝贝的数据输入,其中一个的移动名称为“growl”,而另一个没有移动字段。
我想从下一个客户端读取口袋妖怪集合,并构建一个包含两个形状的数组
{ name: string, move?: { name: string } }
我的初始代码看起来像这样:
import firebase from "./{configfilepath}"
...
const db = getFirestore(firebase)
const pokemonRef = collection(db, "pokemon")
const pokemonQuery = query(pokemonRef)
const pokemonSnap = await getDocs(pokemonQuery)
...
const pokemon = []
pokemonSnap.forEach(async (doc) => {
const docData = doc.data()
const moveRef = docData.move
const moveSnap = moveRef ? await getDoc(moveRef) : undefined
const moveData = moveSnap ? moveSnap.data() : undefined
pokemon.push({
id: doc.id,
name: docData.name,
move: moveData,
})
})
当我执行此代码时,我获得一个只有一个条目的数组,该数组会跳过对等待的调用的调用。
所以问题是 Firestore 的
.forEach
的 QuerySnapshot
方法并不等待承诺解决,但我没有看到另一个可以处理异步操作的内置方法。
所以我转向处理 Firestore 之外的承诺的东西
forEach
:
...
const pokemonRaw = []
pokemonSnap.forEach((doc) => {
pokemonRaw.push({
id: doc.id,
data: doc.data()
})
})
const pokemon = await Promise.all(pokemonRaw.map(async (rawData) => {
const moveRef = rawData.data.move
const moveSnap = moveRef ? await getDoc(moveRef) : undefined
const moveData = moveSnap ? moveSnap.data() : undefined
return {
id: rawData.id,
name: rawData.data.name,
move: moveData,
}
}))
老实说,对于涉及引用字段的相对简单的读取操作来说,这似乎有点太复杂了,所以我的问题是: 在从客户端读取 Firestore 记录时是否有更简洁和惯用的方法来访问引用字段并且我会更好吗?使用 Firestore 建模数据时忘记引用字段?
由于最初的问题有点模糊并要求固执己见的答案,所以唯一真正正确的答案是“这取决于”。
不过,我认为值得一提的是,使用 Firestore 时,通过提供人类可读的字符串而不是关系字段,可以避免在渲染可用字段的简单视图时处理关系层的问题。
对于名称为“growl”的动作,我可以将其存储在神奇宝贝记录中,其字符串值为“growl”,这是我希望用户在神奇宝贝的详细信息中看到的内容。
然后,如果用户有兴趣了解有关该动作的更多详细信息我可以针对与名称字段中的值“growl”匹配的动作触发不同的查询。
或者,您也可以选择使用值“growl”作为记录本身的名称,这将消除读取任何包含字段的值的需要,并且具有唯一的(可能有用的)约束记录一下。
虽然这限制了您可以通过单个查询获取神奇宝贝的内容,但我认为它为用户提供了足够的信息来接收有用且可交互的用户界面。