Skip to content

Commit e11d4b7

Browse files
committed
Refactor: Update fetchIncompleteTasksByUserIds to use batch queries and filter in-memory
- Replaced Firestore query with batch query to fetch incomplete tasks for multiple users at once. - Filter tasks by user IDs and completed statuses in-memory for improved efficiency. - Updated return structure to return an array directly instead of an object with `docs` property. - Updated test cases related to the same.
1 parent 8a8d5ac commit e11d4b7

File tree

4 files changed

+40
-27
lines changed

4 files changed

+40
-27
lines changed

models/tasks.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -702,21 +702,28 @@ const markUnDoneTasksOfArchivedUsersBacklog = async (users) => {
702702
};
703703

704704
/**
705-
* Fetch incomplete tasks assigned to a specific user
706-
* @param {string} userId - The unique identifier for the user.
707-
* @returns {Promise<Array>} - A promise that resolves to an array of incomplete tasks for the given user.
705+
* Fetches all incomplete tasks for given user IDs.
706+
*
707+
* @param {string[]} userIds - The IDs of the users to fetch incomplete tasks for.
708+
* @returns {Promise<firebase.firestore.QuerySnapshot>} - The query snapshot object.
708709
* @throws {Error} - Throws an error if the database query fails.
709710
*/
710-
const fetchIncompleteTaskForUser = async (userId) => {
711+
const fetchIncompleteTasksByUserIds = async (userIds) => {
711712
const COMPLETED_STATUSES = [DONE, COMPLETED];
713+
714+
if (!userIds || userIds.length === 0) {
715+
return [];
716+
}
712717
try {
713-
const incompleteTaskForUser = await tasksModel
714-
.where("assigneeId", "==", userId)
715-
.where("status", "not-in", COMPLETED_STATUSES)
716-
.get();
717-
return incompleteTaskForUser;
718+
const incompleteTasksQuery = await tasksModel.where("assigneeId", "in", userIds).get();
719+
720+
const incompleteTaskForUsers = incompleteTasksQuery.docs.filter(
721+
(task) => !COMPLETED_STATUSES.includes(task.data().status)
722+
);
723+
724+
return incompleteTaskForUsers;
718725
} catch (error) {
719-
logger.error("Error when fetching incomplete tasks:", error);
726+
logger.error("Error when fetching incomplete tasks for users:", error);
720727
throw error;
721728
}
722729
};
@@ -740,5 +747,5 @@ module.exports = {
740747
updateTaskStatus,
741748
updateOrphanTasksStatus,
742749
markUnDoneTasksOfArchivedUsersBacklog,
743-
fetchIncompleteTaskForUser,
750+
fetchIncompleteTasksByUserIds,
744751
};

services/users.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
const firestore = require("../utils/firestore");
22
const { formatUsername } = require("../utils/username");
33
const userModel = firestore.collection("users");
4-
const tasksQuery = require("../models/tasks");
4+
const tasksModel = require("../models/tasks");
55

66
const getUsersWithIncompleteTasks = async (users) => {
77
if (users.length === 0) return [];
8+
89
try {
9-
const eligibleUsersWithTasks = [];
10-
for (const user of users) {
11-
const abandonedTasksQuerySnapshot = await tasksQuery.fetchIncompleteTaskForUser(user.id);
12-
if (!abandonedTasksQuerySnapshot.empty) {
13-
eligibleUsersWithTasks.push(user);
14-
}
10+
const userIds = users.map((user) => user.id);
11+
12+
const abandonedTasksQuerySnapshot = await tasksModel.fetchIncompleteTasksByUserIds(userIds);
13+
14+
if (abandonedTasksQuerySnapshot.empty) {
15+
return [];
1516
}
17+
18+
const userIdsWithIncompleteTasks = new Set(abandonedTasksQuerySnapshot.map((doc) => doc.data().assigneeId));
19+
20+
const eligibleUsersWithTasks = users.filter((user) => userIdsWithIncompleteTasks.has(user.id));
21+
1622
return eligibleUsersWithTasks;
1723
} catch (error) {
18-
logger.error(`Error in getting users who abandoned tasks: ${error}`);
24+
logger.error(`Error in getting users who abandoned tasks: ${error}`);
1925
throw error;
2026
}
2127
};

test/unit/models/tasks.test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,23 +371,23 @@ describe("tasks", function () {
371371
});
372372

373373
it("should fetch tasks which are incomplete for the given user", async function () {
374-
const inactiveUser = abandonedUsersData[0];
375-
const incompleteTasks = await tasks.fetchIncompleteTaskForUser(inactiveUser.id);
376-
expect(incompleteTasks.docs.length).to.be.equal(1);
374+
const userIds = abandonedUsersData.map((user) => user.id);
375+
const incompleteTasks = await tasks.fetchIncompleteTasksByUserIds(userIds);
376+
expect(incompleteTasks.length).to.be.equal(3);
377377
});
378378

379379
it("should return an empty array if there are no tasks incomplete for the user", async function () {
380380
await cleanDb();
381381
const activeUser = abandonedUsersData[2];
382-
const incompleteTasks = await tasks.fetchIncompleteTaskForUser(activeUser.id);
383-
expect(incompleteTasks.docs.length).to.be.equal(0);
382+
const incompleteTasks = await tasks.fetchIncompleteTasksByUserIds([activeUser.id]);
383+
expect(incompleteTasks.length).to.be.equal(0);
384384
});
385385

386386
it("should handle errors gracefully if the database query fails", async function () {
387-
sinon.stub(tasks, "fetchIncompleteTaskForUser").throws(new Error("Database query failed"));
387+
sinon.stub(tasks, "fetchIncompleteTasksByUserIds").throws(new Error("Database query failed"));
388388

389389
try {
390-
await tasks.fetchIncompleteTaskForUser();
390+
await tasks.fetchIncompleteTasksByUserIds();
391391
expect.fail("Expected function to throw an error");
392392
} catch (error) {
393393
expect(error.message).to.equal("Database query failed");

test/unit/services/users.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe("Users services", function () {
150150

151151
it("should throw an error if fetchIncompleteTaskForUser fails", async function () {
152152
const users = abandonedUsersData.slice(0, 2);
153-
Sinon.stub(tasks, "fetchIncompleteTaskForUser").throws(new Error("Database query failed"));
153+
Sinon.stub(tasks, "fetchIncompleteTasksByUserIds").throws(new Error("Database query failed"));
154154

155155
try {
156156
await getUsersWithIncompleteTasks([users]);

0 commit comments

Comments
 (0)