在 Javascript 中从 Firestore 获取 forEach() 之后的数据
Fetching data after forEach() from Firestore in Javascript
我正在构建一个锻炼网络应用程序,需要显示每次锻炼要完成多少轮以及每轮有多少锻炼。
由于每次锻炼的轮数和每轮运动量不同,我将它们设置为 forEach。
但我需要知道回合集合的 docID(显示为“roundID”)才能获取特定集合,子集合才能显示特定练习。
目前它没有显示练习,因为我需要等待第一次提取完成,然后使用我无法做到的那个 docId。
我已经尝试使用循环、异步等待,但无法让它工作。
目前我的代码是:
Main forEach 获得回合
const Rnds = document.getElementById("rnds");
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const unsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const roundID = doc.id;
const rounds = doc.data().round;
const rests = doc.data().rest;
console.log("Round", roundID);
Rnds.innerHTML += `
<h2>${rounds}</h2>
A list of the amount of exercise docs in "exercise" collection
<p>${rests}</p>
`
});
});
然后,获取轮次的练习
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", roundID, "exercises"));
const exerciseUnsub = onSnapshot(exerciseRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const reps = doc.data().rep;
const names = doc.data().exerciseName;
console.log("Exercises", doc.data());
});
});
问题更新
目前,我可以获取轮次以及与它们一起显示在控制台中的正确练习文档。我设法让回合显示,但无法将练习名称传递给 innerHTML。
// Create Exercise Rounds
const Rnds = document.getElementById("rnds");
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const roundsUnsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const DocId = doc.id;
const rounds = doc.data().roundName;
const rests = "Rest: " + doc.data().rest;
// Calls the `runQuery` async function to get the exercises documents.
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
const names = obj.exerciseNames;
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
// Logs the constructed object.
console.log(obj);
// Put your `innerhtml` here.
Rnds.innerHTML += `
<h2>${rounds}</h2>
<p>${names}</p>. // <- unable to get this to show
<p>${rests}</p>
`
});
});
});
async function runQuery(documentId) {
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", documentId, "exercises"));
const querySnapshot = await getDocs(exerciseRef);
if (!querySnapshot) {
return null;
}
// Returns a map of data (array).
return querySnapshot.docs.map((doc) => doc.data());
}
roundsUnsub;
有一种方法可以关联或获取练习集合的数据,但有几点我想指出:
onSnapshot
只监听你在这行代码查询到的所有文档的变化(也就是rounds集合中的文档):
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
- 如果 练习 文档有变化,您将无法从中获得实时更新。
要从轮次集合中获取实时更新并将练习与轮次的文档相关联,您必须创建一个异步函数,您应该在主函数上调用该函数。请参阅下面的代码示例:
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const unsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const DocId = doc.id;
// Calls the `runQuery` async function to get the exercises documents.
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
// Logs the constructed object.
console.log(obj);
// Put your `innerhtml` here.
});
});
});
async function runQuery(documentId) {
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", documentId, "exercises"));
const querySnapshot = await getDocs(exerciseRef);
if (!querySnapshot) {
return null;
}
// Returns a map of data (array).
return querySnapshot.docs.map((doc) => doc.data());
}
我添加了一些注释以更好地理解上面的代码。
正如我在上面指出的一些问题,如果您想从 rounds 集合中获得 real-time 更新,可以使用一些解决方法。您必须修改添加、更新或删除文档的方式。首先,您需要向 exercises 集合添加一个文档,然后将数据更新或设置到新创建的回合的文档中。请参阅下面的示例代码:
// Your document ID for rounds collection
const docId = 'Round 3';
const exercisesRef = collection(db, 'user', uid, 'yourWorkouts', id, 'rounds', docId, 'exercises');
const roundsRef = doc(db, 'users', uid, 'yourWorkouts', id, 'rounds', docId);
// Add a document to the rounds and exercises collection. Sets the data to the exercises document.
addDoc(exercisesRef, {
// Your exercises document data
}, { merge: true })
.then (() => {
// Method above will create a round document but doesn't have data on it (still an invalid document).
// We need to set or update the document to make it a valid document to be able for a snapshot to read the newly added document.
setDoc(roundsRef, {
// Your Rounds document data
}, { merge: true })
.catch((error) => {
console.error("Error writing Rounds document: ", error);
});
})
.catch((error) => {
console.error("Error writing exercises document: ", error);
});
有关更多相关信息,您可能需要查看此文档:
更新:
根据您呈现数据的方式,您只是将一个对象分配给一个变量,该变量又 returns undefined
。您必须首先访问该对象并使用 for
循环,因为练习集合可以包含多个文档。请参阅下面的代码:
// Create Exercise Rounds
const Rnds = document.getElementById("rnds");
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const roundsUnsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const DocId = doc.id;
const rounds = doc.data().roundName;
const rests = "Rest: " + doc.data().rest;
// Calls the `runQuery` async function to get the exercises documents.
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
// Initialize names array to be used in `innerhtml`
const names = [];
// Logs the constructed object.
console.log(obj);
// Loops your exerciseNames and push it in the `names` array
for (const exerciseDocument of obj[DocId]) {
names.push(exerciseDocument.exerciseNames);
}
// Put your `innerhtml` here.
Rnds.innerHTML += `
<h2>${rounds}</h2>
<p>${names}</p>. // This will now show
<p>${rests}</p>
`
});
});
});
async function runQuery(documentId) {
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", documentId, "exercises"));
const querySnapshot = await getDocs(exerciseRef);
if (!querySnapshot) {
return null;
}
// Returns a map of data (array).
return querySnapshot.docs.map((doc) => doc.data());
}
roundsUnsub;
要分隔名称,而不是将名称推入数组,您需要初始化一个字符串并使用 <p>
标记迭代 html 输出并使用 +=
(加法赋值运算符)将结果赋值给变量。请参阅下面的代码:
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
var names = "";
for (const exerciseDocument of obj[DocId])
// Make sure that you type the fieldname correctly.
// Based on your codes given above, you mentioned `exerciseName` and `exerciseNames`
names +=`<p>${exerciseDocument.exerciseNames}</p>`;
}
Rnds.innerHTML +=
`<h2>${rounds}</h2>.
${names}.
<p>${rests}</p>`
});
});
查看此工作代码段。它应该是这样的:
<!DOCTYPE html>
<html>
<body>
<p id="rnds"></p>
<script>
const Rnds = document.getElementById("rnds");
const DocId = 'Round'
const rounds = DocId;
// Sample constructed object based on your Firestore Structure
const obj = {Round :[{exerciseNames: 'exercise1'}, {exerciseNames: 'exercise2'}]};
const rests = 'testRest';
var names = ""
for (const exerciseDocument of obj[DocId]) {
names +=`<p>${exerciseDocument.exerciseNames}</p>`;
}
Rnds.innerHTML +=
`<h2>${rounds}</h2>.
${names}.
<p>${rests}</p>`
</script>
</body>
</html>
我正在构建一个锻炼网络应用程序,需要显示每次锻炼要完成多少轮以及每轮有多少锻炼。
由于每次锻炼的轮数和每轮运动量不同,我将它们设置为 forEach。
但我需要知道回合集合的 docID(显示为“roundID”)才能获取特定集合,子集合才能显示特定练习。
目前它没有显示练习,因为我需要等待第一次提取完成,然后使用我无法做到的那个 docId。
我已经尝试使用循环、异步等待,但无法让它工作。
目前我的代码是:
Main forEach 获得回合
const Rnds = document.getElementById("rnds");
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const unsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const roundID = doc.id;
const rounds = doc.data().round;
const rests = doc.data().rest;
console.log("Round", roundID);
Rnds.innerHTML += `
<h2>${rounds}</h2>
A list of the amount of exercise docs in "exercise" collection
<p>${rests}</p>
`
});
});
然后,获取轮次的练习
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", roundID, "exercises"));
const exerciseUnsub = onSnapshot(exerciseRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const reps = doc.data().rep;
const names = doc.data().exerciseName;
console.log("Exercises", doc.data());
});
});
问题更新
目前,我可以获取轮次以及与它们一起显示在控制台中的正确练习文档。我设法让回合显示,但无法将练习名称传递给 innerHTML。
// Create Exercise Rounds
const Rnds = document.getElementById("rnds");
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const roundsUnsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const DocId = doc.id;
const rounds = doc.data().roundName;
const rests = "Rest: " + doc.data().rest;
// Calls the `runQuery` async function to get the exercises documents.
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
const names = obj.exerciseNames;
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
// Logs the constructed object.
console.log(obj);
// Put your `innerhtml` here.
Rnds.innerHTML += `
<h2>${rounds}</h2>
<p>${names}</p>. // <- unable to get this to show
<p>${rests}</p>
`
});
});
});
async function runQuery(documentId) {
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", documentId, "exercises"));
const querySnapshot = await getDocs(exerciseRef);
if (!querySnapshot) {
return null;
}
// Returns a map of data (array).
return querySnapshot.docs.map((doc) => doc.data());
}
roundsUnsub;
有一种方法可以关联或获取练习集合的数据,但有几点我想指出:
onSnapshot
只监听你在这行代码查询到的所有文档的变化(也就是rounds集合中的文档):const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
- 如果 练习 文档有变化,您将无法从中获得实时更新。
要从轮次集合中获取实时更新并将练习与轮次的文档相关联,您必须创建一个异步函数,您应该在主函数上调用该函数。请参阅下面的代码示例:
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const unsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const DocId = doc.id;
// Calls the `runQuery` async function to get the exercises documents.
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
// Logs the constructed object.
console.log(obj);
// Put your `innerhtml` here.
});
});
});
async function runQuery(documentId) {
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", documentId, "exercises"));
const querySnapshot = await getDocs(exerciseRef);
if (!querySnapshot) {
return null;
}
// Returns a map of data (array).
return querySnapshot.docs.map((doc) => doc.data());
}
我添加了一些注释以更好地理解上面的代码。
正如我在上面指出的一些问题,如果您想从 rounds 集合中获得 real-time 更新,可以使用一些解决方法。您必须修改添加、更新或删除文档的方式。首先,您需要向 exercises 集合添加一个文档,然后将数据更新或设置到新创建的回合的文档中。请参阅下面的示例代码:
// Your document ID for rounds collection
const docId = 'Round 3';
const exercisesRef = collection(db, 'user', uid, 'yourWorkouts', id, 'rounds', docId, 'exercises');
const roundsRef = doc(db, 'users', uid, 'yourWorkouts', id, 'rounds', docId);
// Add a document to the rounds and exercises collection. Sets the data to the exercises document.
addDoc(exercisesRef, {
// Your exercises document data
}, { merge: true })
.then (() => {
// Method above will create a round document but doesn't have data on it (still an invalid document).
// We need to set or update the document to make it a valid document to be able for a snapshot to read the newly added document.
setDoc(roundsRef, {
// Your Rounds document data
}, { merge: true })
.catch((error) => {
console.error("Error writing Rounds document: ", error);
});
})
.catch((error) => {
console.error("Error writing exercises document: ", error);
});
有关更多相关信息,您可能需要查看此文档:
更新:
根据您呈现数据的方式,您只是将一个对象分配给一个变量,该变量又 returns undefined
。您必须首先访问该对象并使用 for
循环,因为练习集合可以包含多个文档。请参阅下面的代码:
// Create Exercise Rounds
const Rnds = document.getElementById("rnds");
const roundRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds"));
const roundsUnsub = onSnapshot(roundRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
const DocId = doc.id;
const rounds = doc.data().roundName;
const rests = "Rest: " + doc.data().rest;
// Calls the `runQuery` async function to get the exercises documents.
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
// Initialize names array to be used in `innerhtml`
const names = [];
// Logs the constructed object.
console.log(obj);
// Loops your exerciseNames and push it in the `names` array
for (const exerciseDocument of obj[DocId]) {
names.push(exerciseDocument.exerciseNames);
}
// Put your `innerhtml` here.
Rnds.innerHTML += `
<h2>${rounds}</h2>
<p>${names}</p>. // This will now show
<p>${rests}</p>
`
});
});
});
async function runQuery(documentId) {
const exerciseRef = query(collection(db, "user", uid, "yourWorkouts", id, "rounds", documentId, "exercises"));
const querySnapshot = await getDocs(exerciseRef);
if (!querySnapshot) {
return null;
}
// Returns a map of data (array).
return querySnapshot.docs.map((doc) => doc.data());
}
roundsUnsub;
要分隔名称,而不是将名称推入数组,您需要初始化一个字符串并使用 <p>
标记迭代 html 输出并使用 +=
(加法赋值运算符)将结果赋值给变量。请参阅下面的代码:
runQuery(DocId).then((result) => {
// Initialized an object
const obj = {};
// Assigns the exercises' documents data to its round collection's documents' Id.
obj[DocId] = result;
var names = "";
for (const exerciseDocument of obj[DocId])
// Make sure that you type the fieldname correctly.
// Based on your codes given above, you mentioned `exerciseName` and `exerciseNames`
names +=`<p>${exerciseDocument.exerciseNames}</p>`;
}
Rnds.innerHTML +=
`<h2>${rounds}</h2>.
${names}.
<p>${rests}</p>`
});
});
查看此工作代码段。它应该是这样的:
<!DOCTYPE html>
<html>
<body>
<p id="rnds"></p>
<script>
const Rnds = document.getElementById("rnds");
const DocId = 'Round'
const rounds = DocId;
// Sample constructed object based on your Firestore Structure
const obj = {Round :[{exerciseNames: 'exercise1'}, {exerciseNames: 'exercise2'}]};
const rests = 'testRest';
var names = ""
for (const exerciseDocument of obj[DocId]) {
names +=`<p>${exerciseDocument.exerciseNames}</p>`;
}
Rnds.innerHTML +=
`<h2>${rounds}</h2>.
${names}.
<p>${rests}</p>`
</script>
</body>
</html>