'How can I return all the subdocuments for an array of objects in Mongoose?

I'm trying to search through the document TreatmentPlan for the subdocument in treatments that matches the clientId provided:

This is the TreatmentPlan model:

const treatmentPlanSchema = mongoose.Schema({
    id: String,
    clientId: String,
    startDate: Date,
    clientGoals: String,
    objectivesOfTreatmentPlan: String,
    conclusionOfTreatmentPlan: String,
    endDate: Date,
    treatments: [treatmentSchema]
})

This is the treatments subdocument:

const treatmentSchema = mongoose.Schema({
    id: String,
    clientId: String,
    date: String,
    time: String,
    price: String
})

And this is the call I'm trying to make in Node:

export const getTreatmentsByClientId = async (req, res) => {
    const { clientId: id } = req.params
    try {
        const result = await TreatmentPlan.find({clientId: id})
        const treatments = result.treatments.find(({clientId})=>clientId === id)
        console.log(treatments)
    } catch (error) {
        console.log(error.message)
    }
} 

When I run this, the error I get is "cannot read property 'find' of undefined."

I ran a similar function on a different array and it worked, but it doesn't seem to work for this array. Any ideas how to make this work?



Solution 1:[1]

You can use this find query:

db.collection.find({
  "clientId": 1,
  "treatments.clientId": 1
},
{
  "_id": 0,
  "treatments.$": 1
})

Where in the projection you are telling mongo "give me the treatments where the condition given (i.e. treatments.clientId: 1) is true".

But be careful, this only returns the first match. Check this example where there are two clientId but only one is returned.

If there are more objects you can use $filter in an aggregate query like this:

  • First $match by "parent" clientId and then filter the treatments array to get only objects where clientId is the desired one.
db.collection.aggregate([
  {
    "$match": {
      "clientId": 1
    }
  },
  {
    "$project": {
      "_id": 0,
      "treatments": {
        "$filter": {
          "input": "$treatments",
          "cond": {"$eq": ["$$this.clientId",1]}
        }
      }
    }
  }
])

Example here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 J.F.