0

hey I am quite new to mongoose and can't get my head around search.

models

User->resumes[]->employments[]

UserSchema

{
    resumes: [ResumeSchema],
    ...
}

ResumeSchema

{
    employments: [EmploymentSchema],
    ...
}

EmploymentSchema

{
    jobTitle: {
        type: String,
        required: [true, "Job title is required."]
    },
    ...
}

Background

User has to enter job title and needs suggestions from the existing data of the already present resumes and their employment's job title

I have tried the following code.

let q = req.query.q; // Software
User.find({ "resumes.employments.jobTitle": new RegExp(req.query.q, 'ig') }, {
    "resumes.employments.$": 1
}, (err, docs) => {
    res.json(docs);
})

Output

[
    {
        _id: '...',
        resumes:[
            {
                employments: [
                    {
                      jobTitle: 'Software Developer',
                      ...
                    },
                    ...
                ]
            },
            ...
        ]
    },
    ...
]

Expected OutPut

["Software Developer", "Software Engineer", "Software Manager"]

Problem 1:) The Data returned is too much as I only need jobTitle

2:) All employments are being returned whereas the query matched one of them

3:) Is there any better way to do it ? via index or via $search ? I did not find much of information in mongoose documentation to create search index (and I also don't really know how to create a compound index to make it work)

I know there might be a lot of answers but none of them helped or I was not able to make them work ... I am really new to mongodb I have been working with relational databases via SQL or through ORM so my mongodb concepts and knowledge is limited.

So please let me know if there is a better solution to do it. or something to make the current one working.

1 Answer 1

2

You can use one of the aggregation query below to get this result:

[
  {
    "jobTitle": [
      "Software Engineer",
      "Software Manager",
      "Software Developer"
    ]
  }
]

Query is:

  • First using $unwind twice to deconstructs the arrays and get the values.
  • Then $match to filter by values you want using $regex.
  • Then $group to get all values together (using _id: null and $addToSet to no add duplicates).
  • And finally $project to shown only the field you want.
User.aggregate({
  "$unwind": "$resumes"
},
{
  "$unwind": "$resumes.employments"
},
{
  "$match": {
    "resumes.employments.jobTitle": {
      "$regex": "software",
      "$options": "i"
    }
  }
},
{
  "$group": {
    "_id": null,
    "jobTitle": {
      "$addToSet": "$resumes.employments.jobTitle"
    }
  }
},
{
  "$project": {
    "_id": 0
  }
})

Example here

Also another option is using $filter into $project stage:

Is similar as before but using $filter instead of $unwind twice.

User.aggregate({
  "$unwind": "$resumes"
},
{
  "$project": {
    "jobs": {
      "$filter": {
        "input": "$resumes.employments",
        "as": "e",
        "cond": {
          "$regexMatch": {
            "input": "$$e.jobTitle",
            "regex": "Software",
            "options": "i"
          }
        }
      }
    }
  }
},
{
  "$unwind": "$jobs"
},
{
  "$group": {
    "_id": null,
    "jobTitle": {
      "$addToSet": "$jobs.jobTitle"
    }
  }
},
{
  "$project": {
    "_id": 0
  }
})

Example here

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

2 Comments

Got it working .. thank you.. just one thing .. The mongoose version I am using was expecting the aggregation pipelines in array of objects not as parameters ...
and thank you very much for detailed explanation ... that really makes a lot of sense now ..

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.