Home > Net >  Get a flat array of deeply nested items in MongoDB
Get a flat array of deeply nested items in MongoDB

Time:06-07

I am building a side project that uses a mongodb database. I am using the MERN stack to build out a web application with my data. I am using Mongoose to get data from my database on a NodeJS/Express server to build my REST API. Here is an example of the data I have. I have deeply nested subdocuments that I need to retrieve. Each user has an array of 'contacts'. Each 'contact' has an array of 'tasks'. I would like to get an array of all tasks that are nested in each user. For example, if a user has 2 contacts, and each contact has 3 tasks, I would like an array with 6 tasks.

{
   userName: 'jdoe',
   uid: 12343,
   contacts: [
      {
          name: 'Jane Doe',
          tasks:[
             {
                taskName: 'Task1'
             },
             {
                taskName: 'Task2'
             },
             {
                taskName: 'Task3'
             },
          
          ]
      },
      {
          name: 'Bob Smith',
          tasks:[
             {
                taskName: 'TaskA'
             },
             {
                taskName: 'TaskB'
             },
             {
                taskName: 'TaskC'
             },
          
          ]
      }
   ]
}

To query my data with Mongoose, I tried something like this

User.findOne({uid: req.params.uid}, 'contacts.tasks', (yasks,err)=>{
  if(err){
    res.send(err)
  }else{
      res.send(tasks)
    }
})

However, this query returns something like this

{
"_id": "353453",
"contacts": [
    {
        "tasks": [
            {
                 taskName: 'Task1'
            }
        ]
    },
    {
        "tasks": [
            {
                 taskName: 'Task1'
            },
            {
                 taskName: 'Task1'
            }
        ]
    },
    {
        "tasks": []
    },
    {
        "tasks": []
    }
   ]
}

I am looking for a response such as this

       [
            {
                 taskName: 'Task1'
            },
            {
                 taskName: 'Task1'
            },
                 taskName: 'Task1'
            },
            {
                 taskName: 'Task1'
            }
        ]  

I am wondering if there is any way I can do this with Mongoose. If not, what kind of javascript can I run to transform my data to be structured like this?

CodePudding user response:

You can use $reduce for this:

User.aggregate([
  {$match: {uid: req.params.uid}},
  {
    $project: {
      tasks: {
        $reduce: {
          input: "$contacts",
          initialValue: [],
          in: {$concatArrays: ["$$value", "$$this.tasks"]}
        }
      },
      _id: 0
    }
  }
])

See how it works on the playground example

  • Related