Home > OS >  Flatten the nested Object in the Array of objects using Mongoose Populate
Flatten the nested Object in the Array of objects using Mongoose Populate

Time:10-21

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": "[email protected]"
            },
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
        {
            "userId": {
                "_id": "633d498fc3935aa2ab1f9af6",
                "name": "supervisor-abdullah",
                "email": "[email protected]"
            },
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
    ]

The result that I want :-

"users": [
        {
            "_id": "634e890c9de1ec46aad0015a",
            "name": "supervisor-abdullah-new",
            "email": "[email protected]",
            "userRole": "supervisor",
            "busy": false,
            "socketId": null
        },
        {
            "_id": "633d498fc3935aa2ab1f9af6",
            "name": "supervisor-abdullah",
            "email": "[email protected]",
            "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": "[email protected]",
  "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": "[email protected]",
  "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.

CodePudding user response:

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!

CodePudding user response:

You would have to use Aggregate query if you want to modify the result.

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',
    },
  },
  {
    $set: {
      userId: { $first: '$userId' },
    },
  },
  {
    $project: {
      createdAt: 0,
      assignedBy: 0,
      updatedAt: 0,
      workspaceId: 0,
      _id: "$userId._id",
      name:"$userId.name",
      email: "$userId.email",
    },
  },
]);

Or another solution is to keep your query and modify data directly in the server after response:

let 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',
    });

users = users.map((item) => ({
  userRole: item.userRole,
  busy: item.busy,
  socketId: item.socketId,
  _id: item.userId._id,
  name: item.userId.name,
  email: item.userId.email,
}))
  • Related