From 95e89f687becfb2a7c11fcebd77748a0f0b06770 Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Mon, 17 Feb 2020 21:14:31 -0300 Subject: [PATCH] [FIX] livechat/rooms endpoint not working with big amount of livechats (#16623) * Remove aggregate to improve performance * Use a cursor to run query only once * Do not use toArray in model Co-authored-by: Diego Sampaio --- app/livechat/server/api/lib/rooms.js | 33 +++++++----- app/models/server/raw/LivechatDepartment.js | 6 ++- app/models/server/raw/LivechatRooms.js | 58 ++++++--------------- 3 files changed, 39 insertions(+), 58 deletions(-) diff --git a/app/livechat/server/api/lib/rooms.js b/app/livechat/server/api/lib/rooms.js index 54a421d8e6c2..72d84803de15 100644 --- a/app/livechat/server/api/lib/rooms.js +++ b/app/livechat/server/api/lib/rooms.js @@ -1,4 +1,4 @@ -import { LivechatRooms } from '../../../../models/server/raw'; +import { LivechatRooms, LivechatDepartment } from '../../../../models/server/raw'; export async function findRooms({ agents, @@ -16,18 +16,7 @@ export async function findRooms({ sort, }, }) { - const total = (await LivechatRooms.findRoomsWithCriteria({ - agents, - roomName, - departmentId, - open, - createdAt, - closedAt, - tags, - customFields, - })).length; - - const rooms = await LivechatRooms.findRoomsWithCriteria({ + const cursor = LivechatRooms.findRoomsWithCriteria({ agents, roomName, departmentId, @@ -44,6 +33,24 @@ export async function findRooms({ }, }); + const total = await cursor.count(); + + const rooms = await cursor.toArray(); + + const departmentsIds = [...new Set(rooms.map((room) => room.departmentId).filter(Boolean))]; + if (departmentsIds.length) { + const departments = await LivechatDepartment.findInIds(departmentsIds, { fields: { name: 1 } }).toArray(); + + rooms.forEach((room) => { + if (!room.departmentId) { + return; + } + const department = departments.find((dept) => dept._id === room.departmentId); + if (department) { + room.department = department; + } + }); + } return { rooms, count: rooms.length, diff --git a/app/models/server/raw/LivechatDepartment.js b/app/models/server/raw/LivechatDepartment.js index 040e156b16df..1b103c034442 100644 --- a/app/models/server/raw/LivechatDepartment.js +++ b/app/models/server/raw/LivechatDepartment.js @@ -1,6 +1,8 @@ import { BaseRaw } from './BaseRaw'; export class LivechatDepartmentRaw extends BaseRaw { - - + findInIds(departmentsIds, options) { + const query = { _id: { $in: departmentsIds } }; + return this.find(query, options); + } } diff --git a/app/models/server/raw/LivechatRooms.js b/app/models/server/raw/LivechatRooms.js index 7f9286d86d05..da9ec4282e41 100644 --- a/app/models/server/raw/LivechatRooms.js +++ b/app/models/server/raw/LivechatRooms.js @@ -1099,73 +1099,45 @@ export class LivechatRoomsRaw extends BaseRaw { } findRoomsWithCriteria({ agents, roomName, departmentId, open, createdAt, closedAt, tags, customFields, options = {} }) { - const match = { - $match: { - t: 'l', - }, + const query = { + t: 'l', }; if (agents) { - match.$match.$or = [{ 'servedBy._id': { $in: agents } }, { 'servedBy.username': { $in: agents } }]; + query.$or = [{ 'servedBy._id': { $in: agents } }, { 'servedBy.username': { $in: agents } }]; } if (roomName) { - match.$match.fname = new RegExp(roomName, 'i'); + query.fname = new RegExp(roomName, 'i'); } if (departmentId) { - match.$match.departmentId = departmentId; + query.departmentId = departmentId; } if (open !== undefined) { - match.$match.open = { $exists: open }; + query.open = { $exists: open }; } if (createdAt) { - match.$match.ts = {}; + query.ts = {}; if (createdAt.start) { - match.$match.ts.$gte = new Date(createdAt.start); + query.ts.$gte = new Date(createdAt.start); } if (createdAt.end) { - match.$match.ts.$lte = new Date(createdAt.end); + query.ts.$lte = new Date(createdAt.end); } } if (closedAt) { - match.$match.closedAt = {}; + query.closedAt = {}; if (closedAt.start) { - match.$match.closedAt.$gte = new Date(closedAt.start); + query.closedAt.$gte = new Date(closedAt.start); } if (closedAt.end) { - match.$match.closedAt.$lte = new Date(closedAt.end); + query.closedAt.$lte = new Date(closedAt.end); } } if (tags) { - match.$match.tags = { $in: tags }; + query.tags = { $in: tags }; } if (customFields) { - match.$match.$and = Object.keys(customFields).map((key) => ({ [`livechatData.${ key }`]: new RegExp(customFields[key], 'i') })); - } - const sort = { $sort: options.sort || { name: 1 } }; - const firstParams = [match, sort]; - if (options.offset) { - firstParams.push({ $skip: options.offset }); + query.$and = Object.keys(customFields).map((key) => ({ [`livechatData.${ key }`]: new RegExp(customFields[key], 'i') })); } - if (options.count) { - firstParams.push({ $limit: options.count }); - } - const lookup = { - $lookup: { - from: 'rocketchat_livechat_department', - localField: 'departmentId', - foreignField: '_id', - as: 'department', - }, - }; - const unwind = { - $unwind: { - path: '$department', - preserveNullAndEmptyArrays: true, - }, - }; - const params = [...firstParams, lookup, unwind]; - if (options.fields) { - params.push({ $project: options.fields }); - } - return this.col.aggregate(params).toArray(); + return this.find(query, { sort: options.sort || { name: 1 }, skip: options.offset, limit: options.count }); } }