2

I have such models:

const UserSchema = new mongoose.Schema({
  name: String,
  workspaces: [
    {
      workspace: {
        type: mongoose.Schema.ObjectId,
      },
      owner: Boolean
    }
  ]
});

const WorkspaceSchema = new mongoose.Schema({
  title: String,
  description: String 
});

I want to populate the User record like this:

{
  name: "John",
  workspaces: [{
    workspace: {
      title: "First space",
      description: "About space#1"
    },
    owner: true
  }, {
    workspace: {
      title: "Second space",
      description: "About space#2"
    },
    owner: false
  }]
}

I tried to do this via populate method:

const user = await User
  .findOne(query)
  .populate({
    path: 'workspaces',
    populate: {
      path: 'workspace',
      model: 'Workspace'
    }
  });

And it's not correct. I searched for case like this, but didn't find anything similar. All another examples doesn't includes property like my boolean "owner".

Harshal Yeole
  • 4,812
  • 1
  • 21
  • 43
b4v
  • 75
  • 1
  • 10
  • Of course, I can move `owner` property to Workspace model with reference to User. But in my actual case I have also `permissions: {read: Boolean, write: Boolean}` property on the same level as `owner` – b4v Aug 09 '18 at 09:35
  • Use $push with $each https://docs.mongodb.com/v3.2/reference/operator/update/push/#up._S_push. Avoid libraries which usually don't make use of modern features which will be atomic in the future and more efficient. – Dominic Aug 09 '18 at 12:03

2 Answers2

0

Use deep-populate

Installation:

npm i mongoose-deep-populate

Usage:

var deepPopulate = require('mongoose-deep-populate')(mongoose);

User.deepPopulate(users, 'workspaces.workspace')
.then(function(err, data) {
    console.log(data);
});

Read more : https://www.npmjs.com/package/mongoose-deep-populate

Hope this solves your query.

Harshal Yeole
  • 4,812
  • 1
  • 21
  • 43
0

I recommend you to add reference to workspace model at the user schema declaration:

 workspace: {
    type: mongoose.Schema.ObjectId,
    ref: "Workspace"
 }

Also, you probably messed up with populate method, because the workspaces array does not contain references to external objects itself. You probably should use this method like this:

const user = await User
  .findOne(query)
  .populate("workspaces.workspace");

Or, if you need any other options, than path, then use with options object:

const user = await User
  .findOne(query)
  .populate({
    path: "workspaces.workspace", ...
  });
ykit9
  • 483
  • 4
  • 7
  • Yes, that's works for me! But as a result I get the structure like the one below. Note the "_id" props. That's similar but not the same! Why does it happen? { name: "John", workspaces: [{ workspace: { **_id: "5b6c3a7d39606df14010fbc0"**, title: "First space", description: "About space#1" }, owner: true, **_id: "5b6c3a7d39606df14010fbc1"** } – b4v Aug 10 '18 at 19:49
  • Thats because mongo creates _id for a nested collections by default. You can disable this behavior by setting _id: false option. Take a look there https://stackoverflow.com/questions/17254008/stop-mongoose-from-creating-id-property-for-sub-document-array-items – ykit9 Aug 11 '18 at 06:24