0

I am creating a MERN app that allows users to sign up and save their skills to a database. I am creating an admin panel that allows me to search for users by skill. User's skills will look like this in the database:

skills: [
  {skill: 'React', yearsExperience: 3},
  {skill: 'HTML', yearsExperience: 5},
  {skill: 'JavaScript', yearsExperience: 5},
  {skill: 'Git', yearsExperience: 3},
  {skill: 'TypeScript', yearsExperience: 1},
  {skill: 'C++', yearsExperience: 1}
]

I have an aggregation query set up that allows me to find all users who match a query by atleast 25%. Meaning if I search for someone with React skills, SQL skills, and C++ skills it will pull back anyone matching at least one of those. My question at this point is how can I modify my aggregation query to create a new field on the document that lists what fields did not match on the query? So this field would show Mark as missing React and SQL skills if he only has C++ experience.

Here is my current query that shows matching users and the percentage they match to the query I search for (in this case greater than 3 years SQL experience, and greater than 2 years GIT experience):

await User.aggregate([
{
  $addFields: {
    matchingSkills: {
      $filter: {
        input: '$skills',
        cond: {
          $or: [
            {
              $and: [
                { $gt: ['$$this.yearsExperience', 3] },
                { $eq: ['$$this.skill', 'SQL'] },
              ],
            },
          {
            $and: [
              { $gt: [ "$$this.yearsExperience", 2] },
              { $eq: [ "$$this.skill", "Git"] }
            ]
          }
          ],
        },
      },
    },
  },
},
{
  $addFields: {
    matchingSkills: '$$REMOVE',
    percentageMatch: {
      $multiply: [
        { $divide: [{ $size: '$matchingSkills' }, skillSearch.length] }, 
        100,
      ],
    },
  },
},
{
  $match: { percentageMatch: { $gte: 25 } },
},
]);
1
  • Im not clear, For example, you are searching with three condition like GIT,React,C++ with some years. Assume that output is GIT and REACT only. Do you expect the c++ should be in new field?? Or can you edit the question and explain more and update the expected output!! Commented May 18, 2021 at 18:25

1 Answer 1

1

To get a list of missing skills,

  1. Add field requiredSkills which will be an array of just the searched skills names.

let requiredSkillsStage = {
  $addFields: {
    matchingSkills: {
      $filter: {
        input: "$skills",
        cond: {
          $or: [{
              $and: [{
                  $gt: ["$$this.yearsExperience", 3]
                },
                {
                  $eq: ["$$this.skill", "SQL"]
                }
              ]
            },
            {
              $and: [{
                  $gt: ["$$this.yearsExperience", 2]
                },
                {
                  $eq: ["$$this.skill", "Git"]
                }
              ]
            }
          ]
        }
      }
    },
    requiredSkills: ["SQL", "Git"]
  }
}

  1. Use $map to get matched skills' names.

let matchingSkillsNamesStage = {
  $addFields: {
    "matchingSkillsNames": {
      $map: {
        input: "$matchingSkills",
        as: "matchingSkill",
        in: "$$matchingSkill.skill"
      }
    }
  }
}

  1. Filter-out matched skills from requiredSkills

let missingSkillsStage = {
  $addFields: {
    "missingSkills": {
      $filter: {
        input: "$requiredSkills",
        cond: {
          $not: {
            $in: [
              "$$this",
              "$matchingSkillsNames"
            ]
          }
        }
      }
    }
  }
}

Try it out to see how the output would look like

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.