From 68d94604a077ba1ac150ed427e1f3a83f3d84b48 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Bajpai Date: Sat, 6 Jun 2026 02:40:33 +0530 Subject: [PATCH] fix: sort top questions by upvote count --- server/routes/questions.js | 21 +++++++++------- server/services/questionQueries.js | 37 ++++++++++++++++++++++++++++ tests/question-query-service.test.js | 23 +++++++++++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 server/services/questionQueries.js create mode 100644 tests/question-query-service.test.js diff --git a/server/routes/questions.js b/server/routes/questions.js index 9d64260..81bda54 100644 --- a/server/routes/questions.js +++ b/server/routes/questions.js @@ -5,6 +5,7 @@ const Answer = require('../models/Answer') const { authenticateToken } = require('../middleware/auth') const { acceptAnswer } = require('../services/answerAcceptance') const { voteOnContent, sendVoteResponse } = require('../services/voting') +const { findQuestionsForList } = require('../services/questionQueries') const router = express.Router() @@ -23,7 +24,8 @@ router.get('/', async (req, res) => { timeRange = 'all' } = req.query - const skip = (page - 1) * limit + const parsedLimit = parseInt(limit) + const skip = (page - 1) * parsedLimit const query = { isDeleted: false } // Search filter @@ -83,7 +85,7 @@ router.get('/', async (req, res) => { sortOption = { createdAt: 1 } break case 'votes': - sortOption = { 'votes.upvotes': -1 } + sortOption = { createdAt: -1 } break case 'answers': sortOption = { answerCount: -1 } @@ -104,15 +106,16 @@ router.get('/', async (req, res) => { break } - const questions = await Question.find(query) - .populate('author', 'username reputation avatar') - .sort(sortOption) - .skip(skip) - .limit(parseInt(limit)) - .lean() + const questions = await findQuestionsForList({ + query, + sort, + sortOption, + skip, + limit: parsedLimit + }) const total = await Question.countDocuments(query) - const totalPages = Math.ceil(total / limit) + const totalPages = Math.ceil(total / parsedLimit) // Add virtual fields const questionsWithVirtuals = questions.map(q => ({ diff --git a/server/services/questionQueries.js b/server/services/questionQueries.js new file mode 100644 index 0000000..1b386a2 --- /dev/null +++ b/server/services/questionQueries.js @@ -0,0 +1,37 @@ +const Question = require('../models/Question') + +const buildTopQuestionsPipeline = (query, skip, limit) => [ + { $match: query }, + { + $addFields: { + upvoteCountForSort: { + $size: { $ifNull: ['$votes.upvotes', []] } + } + } + }, + { $sort: { upvoteCountForSort: -1, createdAt: -1 } }, + { $skip: skip }, + { $limit: limit } +] + +const findQuestionsForList = async ({ query, sort, sortOption, skip, limit }) => { + if (sort !== 'votes') { + return Question.find(query) + .populate('author', 'username reputation avatar') + .sort(sortOption) + .skip(skip) + .limit(limit) + .lean() + } + + const questions = await Question.aggregate(buildTopQuestionsPipeline(query, skip, limit)) + return Question.populate(questions, { + path: 'author', + select: 'username reputation avatar' + }) +} + +module.exports = { + buildTopQuestionsPipeline, + findQuestionsForList +} diff --git a/tests/question-query-service.test.js b/tests/question-query-service.test.js new file mode 100644 index 0000000..4939381 --- /dev/null +++ b/tests/question-query-service.test.js @@ -0,0 +1,23 @@ +const { buildTopQuestionsPipeline } = require('../server/services/questionQueries') + +describe('question list query helpers', () => { + test('top sort computes upvote count instead of sorting by voter object ids', () => { + const query = { isDeleted: false } + + const pipeline = buildTopQuestionsPipeline(query, 20, 10) + + expect(pipeline).toEqual([ + { $match: query }, + { + $addFields: { + upvoteCountForSort: { + $size: { $ifNull: ['$votes.upvotes', []] } + } + } + }, + { $sort: { upvoteCountForSort: -1, createdAt: -1 } }, + { $skip: 20 }, + { $limit: 10 } + ]) + }) +})