Search code examples
javascriptmongodbmongooseaggregation-frameworkmongoose-populate

Flatten the nested Object in the Array of objects using Mongoose Populate


My query

  const users = usersWorkspaceModel
    .find({
      workspaceId,
      userRole: 'supervisor',
    })
    .select({
      _id: 0,
      createdAt: 0,
      assignedBy: 0,
      updatedAt: 0,
      workspaceId: 0,
    })
    .populate({
      path: 'userId',
      select: ['_id', 'name', 'email'],
      mode: 'User',
    });

This returns me the following result :-

 "users": [
        {
            "userId": {
                "_id": "634e890c9de1ec46aad0015a",
                "name": "supervisor-abdullah-new",
                "email": "abdullah_new@gmail.com"
            },
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
        {
            "userId": {
                "_id": "633d498fc3935aa2ab1f9af6",
                "name": "supervisor-abdullah",
                "email": "abdullah-supervisor@gmail.com"
            },
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
    ]

The result that I want :-

"users": [
        {
            "_id": "634e890c9de1ec46aad0015a",
            "name": "supervisor-abdullah-new",
            "email": "abdullah_new@gmail.com",
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
        {
            "_id": "633d498fc3935aa2ab1f9af6",
            "name": "supervisor-abdullah",
            "email": "abdullah-supervisor@gmail.com",
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
    ]

usersWorkspaceModel Collection :-

{
  "_id": {
    "$oid": "634feda89b9ebdf9a12aa7c1"
  },
  "userId": {
    "$oid": "6347bf9befe34bf785fb9a07"
  },
  "userRole": "supervisor",
  "workspaceId": {
    "$oid": "6347de1e81a714995bb497b1"
  },
  "assignedBy": {
    "$oid": "633c3409f2c19af92e788ac6"
  },
  "busy": false,
  "socketId": null,
  "createdAt": {
    "$date": {
      "$numberLong": "1666182568991"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1666187418223"
    }
  }
},{
  "_id": {
    "$oid": "634ea79850cbfd7e532d27a7"
  },
  "userId": {
    "$oid": "633d498fc3935aa2ab1f9af6"
  },
  "userRole": "supervisor",
  "workspaceId": {
    "$oid": "633fd3235788f7cd7222c19e"
  },
  "assignedBy": {
    "$oid": "633c3409f2c19af92e788ac6"
  },
  "busy": false,
  "socketId": null,
  "createdAt": {
    "$date": {
      "$numberLong": "1666099096965"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1666247564289"
    }
  }
}

Users Collection:-

{
  "_id": {
    "$oid": "63354ddcdddc0907714a8622"
  },
  "name": "warda2",
  "email": "client@gmail.com",
  "password": "$2b$10$BSEMsaytAXm.vaZKLDCuzu7LG4SPzvsXrLEOYK/3F5Fq4FGDdGuTO",
  "companyPosition": null,
  "companyName": null,
  "industry": null,
  "country": null,
  "currency": [],
  "profileImageUrl": null,
  "profileImageName": null,
  "role": "client",
  "isEmployee": false,
  "status": "Active",
  "firebaseToken": "fXxT5ZRQJSKMDOaXKOkWxF:APA91bGkZDWuceOGTd_hTwHhjCRKo4c6rbsyBSdFBL8l45oBxqKvpxHnjYLfUzAU6whHwGmpM07wasEw9nne4U8qRdhz_vf5hSJs3NLVZ94DsxtryxxIDM_WVM1A2E76mVJ39_46FMmU",
  "resetPasswordToken": null,
  "resetPasswordExpires": null,
  "emailVerificationToken": null,
  "emailTokenExpiry": null,
  "createdAt": {
    "$date": {
      "$numberLong": "1664437724388"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1666247312218"
    }
  },
  "deleted": true
},{
  "_id": {
    "$oid": "6346c87dca22a36cf627bd8b"
  },
  "name": "supervisor-hassan",
  "email": "hassan@gmail.com",
  "password": "$2b$10$VQ0MiXKlGKc0A0EmOr.4i.kImCQtjRqYQVNlURfoPfpfvszcHoI9.",
  "companyPosition": null,
  "companyName": null,
  "industry": null,
  "country": null,
  "currency": [],
  "profileImageUrl": null,
  "profileImageName": null,
  "role": "supervisor",
  "isEmployee": false,
  "status": "Active",
  "firebaseToken": null,
  "resetPasswordToken": null,
  "resetPasswordExpires": null,
  "emailVerificationToken": null,
  "emailTokenExpiry": null,
  "deleted": true,
  "createdAt": {
    "$date": {
      "$numberLong": "1665583229322"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1665583352347"
    }
  }
}

I want the nested object userId to be flattened using mongoose. How can I achieve this ? I want the data present in the userId object to be placed on the same top level object (not in any nested object). I just want to restructure the data which is being returned by my query.


Solution

  • const ObjectId = require('mongoose').Types.ObjectId;
    
    
     const users = usersWorkspaceModel.aggregate([
        {
          $match: {
            workspaceId: ObjectId(workspaceId),
            userRole: 'supervisor',
          },
        },
        {
          $lookup: {
            from: 'users',
            localField: 'userId',
            foreignField: '_id',
            as: 'userId',
          },
        },
        {
          $unwind: '$userId',
        },
        {
          $replaceRoot: {
            newRoot: {
              $mergeObjects: ['$$ROOT', '$userId'],
            },
          },
        },
        {
          $project: {
            _id: 1,
            busy: 1,
            socketId: 1,
            name: 1,
            email: 1,
            userRole: 1,
          },
        },
      ]);
    

    The $unwind spreads the userId array into an object and $replaceRoot merges that object with the root Object. The $project selects the keys to output!