按点赞量排序分页加载时出现重复Key错误求助
问题描述
我设置了四个筛选器:按最高点赞、最低点赞、最新、最旧排序。测试阶段数据库中答案最多1个点赞、无点赞或1个点踩。选择「最新」或「最旧」筛选时,无限滚动分页正常;但选择「最高点赞」或「最低点赞」时,翻到第2-3页会出现「Encountered two children with the same key, '123456blabla'」错误。
原因分析
核心问题是排序字段的唯一性不足:
- 按
createdAt排序时,每个文档的创建时间都是唯一的,数据库能稳定返回有序结果,分页时不会出现重复数据。 - 按
upvotes排序时,测试数据里大量答案的点赞数相同(都是0、1或-1),此时MongoDB的排序是不稳定的——当排序字段值相同时,MongoDB不会默认按其他字段排序,每次查询的结果顺序可能随机变化。 - 这就导致分页时,前一页的某些数据会出现在后一页的结果里,当无限滚动把新数据追加到列表时,就出现了重复的
_id作为React元素的key,触发重复key错误。
解决办法
给点赞相关的排序规则添加第二排序字段,保证排序的稳定性,比如结合createdAt或MongoDB的唯一_id:
修改服务器端排序逻辑
"use server" export async function getAnswers(params: GetAnswersParams) { try { connectToDatabase(); const { questionId, sortBy, page = 1, pageSize = 5 } = params; const skipAmount = (page - 1) * pageSize; let sortOptions = {}; switch (sortBy) { case 'highestUpvotes': // 先按点赞降序,再按创建时间降序,保证相同点赞数的结果顺序稳定 sortOptions = { upvotes: -1, createdAt: -1 }; break; case 'lowestUpvotes': // 先按点赞升序,再按创建时间升序 sortOptions = { upvotes: 1, createdAt: 1 }; break; case 'recent': sortOptions = { createdAt: -1 }; break; case 'old': sortOptions = { createdAt: 1 }; break; default: break; } const answers = await Answer.find({ question: questionId }) .populate('author', '_id clerkId name picture') .sort(sortOptions) .skip(skipAmount) .limit(pageSize); const totalAnswers = await Answer.countDocuments({ question: questionId, }); const isNext = totalAnswers > skipAmount + answers.length; return { answers: JSON.parse(JSON.stringify(answers)), isNext, }; } catch (error) { console.log(error); throw error; } }
可选优化
如果不想用createdAt,也可以直接用MongoDB的唯一_id作为第二排序字段,效果更稳定:
// 最高点赞排序 sortOptions = { upvotes: -1, _id: -1 }; // 最低点赞排序 sortOptions = { upvotes: 1, _id: 1 };
这样修改后,相同点赞数的答案每次查询的顺序都会保持一致,分页时不会出现重复数据,React列表的key也就不会重复了。
内容的提问来源于stack exchange,提问作者Andreul-
相关产品推荐
相关产品推荐

