0

I have written api in node js with mongoose in which a collection have lot of foreign fields references. Populating them is needed for client side and it is causing delay in response time.

I have tried fetching only those documents of other collections which are referenced in main collection.

Following is the piece of code in which Lead is main collection and it contains references of other collections like project, list, assignee. I am trying to populate documents of these references along with leads collection data.

return db.model('Lead').aggregate([
      {
        $facet: {
          totalData: [
            { $match: queryObj },
            { $group: { _id: { email: "$email", phone: "$phone" }, count: { $sum: 1 }, leads: { $push: { _id: "$_id", name: "$name", firstName: "$firstName", lastName: "$lastName", email: "$email", project: "$project", list: "$list", assignee: "$assignee", phoneCode: "$phoneCode", phone: "$phone", createdAt: "$createdAt", updatedAt: "$updatedAt", utmSource: "$utmSource", source: "$source", unreadmembers: "$unreadmembers" } } } },
            { $sort: sortObj },
            { $skip: (page - 1) * count },
            { $limit: count }
          ],
          totalCount: [
            { $match: queryObj },
            { $group: { _id: { email: "$email", phone: "$phone" } } },
            { $count: "leadsCount" }
          ]
        }
      }
    ]).collation({ locale: "en" }).allowDiskUse(true).exec(async (err, leadsData) => {

      if (err)
        return res.apiError('Failed to get leads!');

      else {
        let leads = (leadsData[0] && leadsData[0].totalData && leadsData[0].totalData.length) ? leadsData[0].totalData : [];

        let leadsCount = (leadsData[0] && leadsData[0].totalCount && leadsData[0].totalCount.length && leadsData[0].totalCount[0] && leadsData[0].totalCount[0].leadsCount) ? leadsData[0].totalCount[0].leadsCount : 0;

        let leadsNew = leads.map(obj => obj.leads);

        leadsNew = [].concat(...leadsNew);

        let assignees = {};

        let assigneeIds = leadsNew.filter(ele => ele.assignee && (ele.assignee !== '' || ele.assignee !== null)).map(l => l.assignee);

        assigneeIds.forEach(_id => (assignees[_id.toString()] = _id));

        let assigneesList = Object.values(assignees);

        assigneesList = await db.model('User').find({ _id: { $in: assigneesList } }, { email: 1 }).lean();

        let projects = {};

        let projectIds = leadsNew.filter(ele => ele.project && (ele.project !== '' || ele.project !== null)).map(l => l.project);
        projectIds.forEach(_id => (projects[_id.toString()] = _id));

        let projectsList = Object.values(projects);

        projectsList = await db.model('Project').find({ _id: { $in: projectsList } }, { name: 1 }).populate({ path: 'teams', select: { name: 1, members: 1 } }).lean();

        let leadLists = {};

        let listIds = leadsNew.filter(ele => ele.list && (ele.list !== '' || ele.list !== null)).map(l => l.list);

        listIds.forEach(_id => (leadLists[_id.toString()] = _id));

        let lists = Object.values(leadLists);

        lists = await db.model('List').find({ _id: { $in: lists } }, { name: 1 }).lean();

        leads.map(l => {
          l.leads.map(p => {
            if (p.assignee)
              p.assignee = assigneesList.find(a => a._id.toString() === p.assignee.toString()) || '';

            if (p.project)
              p.project = projectsList.find(a => a._id.toString() === p.project.toString()) || '';

            if (p.list)
              p.list = lists.find(a => a._id.toString() === p.list.toString()) || '';

          })
        })
        return res.apiOk({ leads, count: leadsCount });
      }
    })

I want to reduce response time of this api. Any idea for solving this is welcome.

0 Answers0