我有这个Express函数:
exports.getSliderTipsteriData = (req, res) => {
let sliderTipsteriData = [];
db.collection("tipsterBanner")
.orderBy("createdAt", "desc")
.where("show", "==", true)
.get()
.then((data) => {
data.forEach((doc) => {
let eventId = doc.data().eventId;
sliderTipsteriData = doc.data();
db.collection("evenimenteTipsteri")
.orderBy("createdAt", "desc")
.get()
.then((data) => {
sliderTipsteriData.tipsteri = [];
data.forEach((doc) => {
if(doc.data().bilet[0].id === sliderTipsteriData.eventId) {
sliderTipsteriData.tipsteri.push({
tipster: doc.data().tipster,
homeTeam: doc.data().bilet[0].homeTeam,
awayTeam: doc.data().bilet[0].awayTeam
})
} else null
})
return res.json(sliderTipsteriData);
})
})
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code });
});
};
并收到此响应:
{
"imageUrl": "https://firebasestorage.googleapis.com/v0/b/socialape-bea5b.appspot.com/o/slider1.jpg?alt=media&token=0824a93d-4bc3-49fa-9ae8-4408961a0736",
"event_date": 1614110400,
"awayTeamName": "Bayer Leverkusen",
"awayTeamPercent": 23,
"homeTeamName": "Atletico Madrid",
"homeTeamShortName": "ATL",
"awayTeamEmblem": "https://media.api-sports.io/football/teams/34.png",
"createdAt": "2021-03-22T18:25:03.667Z",
"homeTeamEmblem": "https://media.api-sports.io/football/teams/49.png",
"awayTeamShortName": "LEV",
"homeTeamPercent": "77",
"show": true,
"eventId": 652238,
"homeTeamColor": "#0099ff",
"awayTeamColor": "#ff0000",
"etapa": "Liga Campionilor, Etapa 2",
"tipsteri": [
{
"tipster": "daniel",
"homeTeam": "Lazio",
"awayTeam": "Bayern Munich"
},
{
"tipster": "user",
"homeTeam": "Lazio",
"awayTeam": "Bayern Munich"
}
]
}
问题是我在中有多个文档tipsterBanner但我只收到第一个。因此,forEach文档可能无法正常工作。
你知道我错过了什么吗?我希望收到响应sliderTipsteriData包含多个对象的数组,而不仅仅是第一个对象。看起来forEach实际上并不循环。
这是因为您的承诺试图在不等待它们的循环中运行。在你的then
块内,你执行更多的异步调用(collection().get()
),但你的代码不是等待他们解决,所以它只是飞过你的forEach
循环,创建那些承诺,但然后到达结束并返回。
有两种方法来解决这个问题-(1)把你的then/catch
调用到Promise.all
,等待解决或(2)切换到async/await。但我觉得你有更好的办法。现在,您正在每个循环中查询evenimenteTipsteri
集合,但是您没有使用tipsterBanner
集合中的任何信息作为evenimenteTipsteri
查询中的参数,因此您可以一次同时查询它们,然后在代码中处理所有过滤/组织。这将有助于加快您的结果和帮助保护您从不必要的读取Firestore上的成本。
这段代码是未经测试的,因为我只是复制/粘贴了你的代码并重写了它,而不能运行它,但这是主要思想:
exports.getSliderTipsteriData = (req, res) => {
let sliderTipsteriData = [];
// These create the promises which will resolve in our Promise.all()
const tipsterBanner = db.collection("tipsterBanner").orderBy("createdAt", "desc").where("show", "==", true).get()
const evenimenteTipsteri = db.collection("evenimenteTipsteri").orderBy("createdAt", "desc").get()
Promise.all([tipsterBanner, evenimenteTipsteri]).then((results) => {
// results is now an array of your original "data" items from your then blocks
// results[0] is the data from the tipsterBanner query
// results[1] is the data from the evenimenteTipsteri query
const tipsterBannerResults = results[0] // Just to make it more readable
const evenimenteTipsteriResults = results[1] // Just to make it more readable
tipsterBannerResults.forEach(doc => {
let eventId = doc.data().eventId
sliderTipsteriData = doc.data() // Is this right? You could end up overwriting your data
sliderTipsteriData.tipsteri = []
evenimenteTipsteriResults.forEach(doc => {
if(doc.data().bilet[0].id === sliderTipsteriData.eventId) {
sliderTipsteriData.tipsteri.push({
tipster: doc.data().tipster,
homeTeam: doc.data().bilet[0].homeTeam,
awayTeam: doc.data().bilet[0].awayTeam
})
}
})
})
return res.json(sliderTipsteriData)
}).catch(error => {
// Handle errors from your queries
})
}