0

I am currently using mongoose v4.10.8 and am attempting to populate multiple arrays on a defined model.

TransportModel.js

//Transport model
'use strict';
const mongoose = require('mongoose');

const TransportSchema = new mongoose.Schema({
    tag: {
        type: String,
        enum: ['X', 'Y'],
        required: true,
        unique: true
    },
    chairs: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: "Chair"
    }],
    targets: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: "Target"
    }]
});

module.exports = mongoose.model('Transport', TransportSchema);

ChairModel.js

//Chair model
'use strict';
const mongoose = require('mongoose');

const ChairSchema = new mongoose.Schema({
    product_name: {
        type: String,
        required: true,
        unique: true
    },
    description: {
      type: String,
      unique: false,
      required: false
    }
});

module.exports = mongoose.model('Chair', ChairSchema);

TargetModel.js

//Target model
'use strict';
const mongoose = require('mongoose');

const TargetSchema = new mongoose.Schema({
    target_name: {
        type: String,
        required: true,
        unique: true
    },
    location: {
      type: String,
      required: true,
      unique: false
    },
    description: {
      type: String,
      unique: false,
      required: false
    }
});

module.exports = mongoose.model('Target', TargetSchema);

After having the above configuration in place, I created one Chair document and one Target document.

Afterwards, I invoke the following logic on a route to get a single Transport document:

TransportModel.findOne({
        tag: 'X'
    })
    .populate("chairs")
    .populate("targets")
    .exec(function(err, transport) {
        if (err) {
            console.error(err);
        }
        console.log('Transport: ', transport);
    });
});

Below is the retrieved document:

{
    "_id": "xxxx9999xxxx9999xxxx9999",
    "tag": "X",
    "__v": 1,
    "chairs": [],
    "targets": []
}

Thus, even though I queried the Chairs and Targets collections and I do have at least 1 document, the Transport document does not get populated.

Furthermore, I also tried the enhanced version of .populate(), but I keep getting empty arrays:

.populate({
  path: "chairs",
  model: "Chair"
})
.populate({
  path: "targets",
  model: "Target"
})
vladzam
  • 5,462
  • 6
  • 30
  • 36
  • How did you add the `Chair` and `Target` documents to the `TransportModel` document? – robertklep Jul 15 '17 at 12:21
  • Thank you for your reply, @robertklep. That is what I am trying to achieve with `.populate()`, I want the `chairs` and `targets` arrays of the `Transport` documents to be automatically populated with the entire available list of `Chair` and `Target` documents from their respective collections. – vladzam Jul 16 '17 at 07:53
  • That's not what population does, though. It's a means to associate _particular_ documents across collections. In other words, you have to manually associate a new `Chair` document with a `TransportModel` document. The `.populate()` method will then add the associated documents automatically during queries. See the documentation: http://mongoosejs.com/docs/populate.html – robertklep Jul 16 '17 at 07:56
  • Thank you for your quick reply. If I understood correctly, it means I first have to push all the `_id` values associated with `Chair` documents in the `chairs` array, and afterwards `.populate()` simply brings the rest of the document properties from the `chairs` collection? That means that I still have to fire `.find({})` query and push the chairs to the `chairs` array? – vladzam Jul 16 '17 at 08:00
  • If by the last line you mean that you already have lots of chairs and want to add them to a `TransportModel` document, then yes. But if you want to associate _all_ chairs and targets with a particular `TransportModel` document, population doesn't really seem to make sense, and you probably should run three different queries (one for each collection/model). – robertklep Jul 16 '17 at 08:02
  • I understand - thanks a lot for the clarification. What I am trying to achieve is the following - whenever a `Chair` document is added to the `chairs` collection, I want it to be made available as part of the `Transport` document in the `chairs` array. Thus, I think here it should be best to define a custom action on `.save()` for `Chair` to also add that element to the `chairs` array on `Transport` documents. Would it make more sense to simply manage those values with a custom schema as part of the arrays? Or separate them in a collection? – vladzam Jul 16 '17 at 08:04
  • @robertklep Thanks a lot for the valuable input! I managed to get it working as intended following your advice. – vladzam Jul 16 '17 at 14:18

1 Answers1

-1

If you already push the new chairs and targets into the Transport model, you can populate it better with the mongoose-deep-populate module, here is a simple example of how config to set it up.

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

var Schema = mongoose.Schema;

var kindsSchema = new Schema({

    name:{type:String,required:true,unique:true},
    components:[{type:Schema.ObjectId,ref:'components'}],
    associatedView:{type:String,default:'home/fragances'},
    discount:{type:Number,default:0},
    description:{type:String,default:'Nueva categoria'},

    created_at:{type:Date,default:Date.now},
    modified_at:{type:Date,required:true}
});

kindsSchema.plugin(deepPopulate,{
  whitelist:[
    'components.attributes',
  ]
    populate:{
      'components':{
      select['attributes','discount']
      }
    }
});

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