buunguyen / mongoose-deep-populate

Mongoose plugin to enable deep population of nested models ⛺
MIT License
469 stars 44 forks source link

Cannot populate nested parent model #12

Closed Exegetech closed 9 years ago

Exegetech commented 9 years ago

Hello,

I am trying to use mongoose-deep-populate, but got this error

Error: Plugin was not installed
    at Query.deepPopulate (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/mongoose-deep-populate/lib/plugin.js:16:61)
    at Object.exports.show [as handle] (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/server/api/user/user.controller.js:45:5)
    at next_layer (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/route.js:103:13)
    at Route.dispatch (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/route.js:107:5)
    at c (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:195:24)
    at param (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:268:14)
    at param (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:280:16)
    at Function.proto.process_params (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:296:3)
    at next (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:189:19)
    at next (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:166:38)
    at next (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:166:38)
    at next_layer (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/route.js:77:14)
    at next_layer (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/route.js:81:14)
    at next_layer (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/route.js:81:14)
    at Route.dispatch (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/route.js:107:5)
    at c (/Users/christianmsakai/Desktop/Baby Mart/ninthbeat/node_modules/express/lib/router/index.js:195:24)

My code is

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crypto = require('crypto');
var _ = require('lodash');
var extend = require('mongoose-schema-extend');
var deepPopulate = require('mongoose-deep-populate');
var authTypes = ['facebook', 'google', 'twitter'];

// User Schema
var UserSchema = new Schema({
  userName: { type: String, trim: true },
  items: [{ type: Schema.Types.ObjectId, ref: 'Item' }],
});

/**
 * Plugins
 */
UserSchema.plugin(deepPopulate);
exports.show = function (req, res, next) {
  var userId = req.params.id;

  User
    .findById(userId)
    .deepPopulate('items.seller')
    .exec(function (err, user) {
    if (err) return next(err);
    if (!user) return res.send(401);
    res.json(user.profile);
  });
};
'use strict';

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var ItemSchema = new Schema({
    seller: { type: Schema.Types.ObjectId, ref: 'User' },
    type: String,
  title:  { type: String, trim: true },
    condition: String,
  description: { type: String, trim: true },
  price: Number,
  imageUrls: [String],
  userLikes: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Item', ItemSchema);

Any ideas?

buunguyen commented 9 years ago

I don't see anything wrong. Did you register the model for the schema, like mongoose.model('User', UserSchema);? Does any other plugin work with this model? It would help if you post a full running code example so that I can run/debug.

Exegetech commented 9 years ago

Hi, Thanks for the prompt response.

So my full code was this

'use strict';

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crypto = require('crypto');
var _ = require('lodash');
var extend = require('mongoose-schema-extend');
var deepPopulate = require('mongoose-deep-populate');
var authTypes = ['facebook', 'google', 'twitter'];

// Address Schemas
var AddressSchema = new Schema({
    street1: String,
    street2: String,
    city: String,
    state: String,
    zip: String,
    country: { type: String, default: 'US' }
});

// Review Schema
var ReviewSchema = new Schema({
    reviewer: { type: Schema.Types.ObjectId, ref: 'User' },
    text: String,
    rating: { type: Number, min: 0, max: 5 },
    status: {
        type: String,
        enum: ['created at', 'edited at'],
        default: 'created at'
    },
    date: { type: Date, default: Date.now },
    transaction: { type: Schema.Types.ObjectId, ref: 'Transaction'}
});

// Notification Schema
var NotificationSchema = new Schema({
  message: String,
  status: {
    type: String,
    enum: ['unread', 'read', 'discarded'],
    default: 'unread',
    required: true
  },
  date: { type: Date, default: Date.now }
});

// User Schema
var UserSchema = new Schema({
  firstName: { type: String, trim: true },
  lastName: { type: String, trim: true },
  userName: { type: String, trim: true },
  email: { type: String, lowercase: true, trim: true },
  profilePicture: { type: String, lowercase: true, trim: true },
  role: {
    type: String,
    default: 'user'
  },
  hashedPassword: String,
  provider: String,
  salt: String,
  facebook: {},
  google: {},
  twitter: {},
  phone: { type: String, trim: true },
  shippingAddresses: [AddressSchema],
  billingAddresses: [AddressSchema],
  description: { type: String, trim: true },
  blog: { type: String, trim: true },
  followers: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  following: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  likes: [{ type: Schema.Types.ObjectId, ref: 'Item' }],
  items: [{ type: Schema.Types.ObjectId, ref: 'Item' }],
  reviews: [ReviewSchema],
  billingInfo: {
    stripeToken: String,
    lastFour: Number,
    cardType: String
  },
  transactions: [{ type: Schema.Types.ObjectId, ref: 'Transaction'}]
});

/**
 * Plugins
 */
UserSchema.plugin(deepPopulate);

/**
 * Virtuals
 */
UserSchema
  .virtual('password')
  .set(function(password) {
    this._password = password;
    this.salt = this.makeSalt();
    this.hashedPassword = this.encryptPassword(password);
  })
  .get(function() {
    return this._password;
  });

// Public profile information
UserSchema
  .virtual('profile')
  .get(function() {
    return {
      'firstName': this.firstName,
      'lastName': this.lastName,
      'userName': this.userName,
      'profilePicture': this.profilePicture,
      'description': this.description,
      'blog': this.blog
    };
  });

// Non-sensitive info we'll be putting in the token
UserSchema
  .virtual('token')
  .get(function() {
    return {
      '_id': this._id,
      'role': this.role
    };
  });

/**
 * Validations
 */
// Validate empty username
UserSchema
  .path('userName')
  .validate(function(userName) {
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return userName.length;
  }, 'Username cannot be blank');

// Validate empty email
UserSchema
  .path('email')
  .validate(function(email) {
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return email.length;
  }, 'Email cannot be blank');

// Validate empty password
UserSchema
  .path('hashedPassword')
  .validate(function(hashedPassword) {
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return hashedPassword.length;
  }, 'Password cannot be blank');

// Validate username is not taken
UserSchema
  .path('userName')
  .validate(function(value, respond) {
    var self = this;
    this.constructor.findOne({userName: value}, function(err, user) {
      if(err) throw err;
      if(user) {
        if(self.id === user.id) return respond(true);
        return respond(false);
      }
      respond(true);
    });
}, 'The specified username is already in use.');

// Validate email is not taken
UserSchema
  .path('email')
  .validate(function(value, respond) {
    var self = this;
    this.constructor.findOne({email: value}, function(err, user) {
      if(err) throw err;
      if(user) {
        if(self.id === user.id) return respond(true);
        return respond(false);
      }
      respond(true);
    });
}, 'The specified email address is already in use.');

var validatePresenceOf = function(value) {
  return value && value.length;
};

/**
 * Pre-save hook
 */
UserSchema
  .pre('save', function(next) {
    if (!this.isNew) return next();

    if (!validatePresenceOf(this.hashedPassword) && authTypes.indexOf(this.provider) === -1)
      next(new Error('Invalid password'));
    else
      next();
  });

var objIndexSearch = function(arr, obj, prop) {
    return _.findIndex(arr, function(item) {
        return item[prop].toString() === obj[prop].toString();
    });
};

/**
 * Methods
 */
UserSchema.methods = {
  /**
   * Authenticate - check if the passwords are the same
   *
   * @param {String} plainText
   * @return {Boolean}
   * @api public
   */
  authenticate: function(plainText) {
    return this.encryptPassword(plainText) === this.hashedPassword;
  },

  /**
   * Make salt
   *
   * @return {String}
   * @api public
   */
  makeSalt: function() {
    return crypto.randomBytes(16).toString('base64');
  },

  /**
   * Encrypt password
   *
   * @param {String} password
   * @return {String}
   * @api public
   */
  encryptPassword: function(password) {
    if (!password || !this.salt) return '';
    var salt = new Buffer(this.salt, 'base64');
    return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64');
  },

  /**
    * Addresses
    */
  addAddress: function(address, addressType, done) {
    this[addressType + "es"].addToSet(address);
    return this.save(done);
  },

  editAddress: function(address, addressType, done) {
    var indexToEdit = objIndexSearch(this[addressType + "es"], address, '_id');

    this[addressType + "es"].set(indexToEdit, address);
    return this.save(done);
  },

  makeAddressPrimary: function(address, addressType, done) {
    var indexToRemove = objIndexSearch(this[addressType + "es"], address, '_id');

    var removedAddress = this[addressType + "es"].splice(indexToRemove, 1)[0];

    this[addressType + "es"].unshift(removedAddress);
    return this.save(done);
  },

  removeAddress: function(address, addressType, done) {
    this[addressType + "es"].id(address._id).remove();
    return this.save(done);
  },

  /**
    * Reviews
    */
  addReview: function(user, review, done) {
    return this.model('User')
        .findByIdAndUpdate(user._id, {
            $addToSet: {
                reviews: _.assign({
                    reviewer: this._id
                }, review)
            }
        }, done);
  },

  editReview: function(user, review, done) {
    return this.model('User')
        .findOneAndUpdate({
            _id: user._id,
            "reviews.reviewer": this._id,
            "reviews._id": review._id
        }, {
            $set: {
                "reviews.$": review
            }
        }, done);
  },

  removeReview: function(user, review, done) {
    return this.model('User')
        .findByIdAndUpdate(user._id, {
            $pull: {
                reviews: {
                    reviewer: this._id,
                    _id: review._id
                }
            }
        }, done);
  },

  /**
    * Followers
    */
  follow: function(user, done) {
    var self = this;
    this.following.addToSet(user._id);
    return this.save(function(err, currentUser) {
        if (err) return done(err);

        self.model('User')
            .findByIdAndUpdate(user._id, {
                $addToSet: { followers: self._id }
            }, function(err, user) {
                done(err, currentUser);
            });
    });
  },

  unFollow: function(user, done) {
    var self = this;
    this.following.pull(user._id);
    return this.save(function(err, currentUser) {
        if (err) return done(err);

        self.model('User')
            .findByIdAndUpdate(user._id, {
                $pull: { followers: self._id }
            }, function(err, user) {
                done(err, currentUser);
            });
    });
  },

  /**
    * Like
    */
  like: function(item, done) {
    this.likes.addToSet(item._id);
    return this.save(done);
  },

  unLike: function(item, done) {
    this.likes.pull(item._id);
    return this.save(done);
  }
};

module.exports = mongoose.model('User', UserSchema);

Strangely, after I moved UserSchema.plugin(deepPopulate); to the bottom of the file, hence

'use strict';

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crypto = require('crypto');
var _ = require('lodash');
var extend = require('mongoose-schema-extend');
var deepPopulate = require('mongoose-deep-populate');
var authTypes = ['facebook', 'google', 'twitter'];

// Address Schemas
var AddressSchema = new Schema({
    street1: String,
    street2: String,
    city: String,
    state: String,
    zip: String,
    country: { type: String, default: 'US' }
});

// Review Schema
var ReviewSchema = new Schema({
    reviewer: { type: Schema.Types.ObjectId, ref: 'User' },
    text: String,
    rating: { type: Number, min: 0, max: 5 },
    status: {
        type: String,
        enum: ['created at', 'edited at'],
        default: 'created at'
    },
    date: { type: Date, default: Date.now },
    transaction: { type: Schema.Types.ObjectId, ref: 'Transaction'}
});

// Notification Schema
var NotificationSchema = new Schema({
  message: String,
  status: {
    type: String,
    enum: ['unread', 'read', 'discarded'],
    default: 'unread',
    required: true
  },
  date: { type: Date, default: Date.now }
});

// User Schema
var UserSchema = new Schema({
  firstName: { type: String, trim: true },
  lastName: { type: String, trim: true },
  userName: { type: String, trim: true },
  email: { type: String, lowercase: true, trim: true },
  profilePicture: { type: String, lowercase: true, trim: true },
  role: {
    type: String,
    default: 'user'
  },
  hashedPassword: String,
  provider: String,
  salt: String,
  facebook: {},
  google: {},
  twitter: {},
  phone: { type: String, trim: true },
  shippingAddresses: [AddressSchema],
  billingAddresses: [AddressSchema],
  description: { type: String, trim: true },
  blog: { type: String, trim: true },
  followers: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  following: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  likes: [{ type: Schema.Types.ObjectId, ref: 'Item' }],
  items: [{ type: Schema.Types.ObjectId, ref: 'Item' }],
  reviews: [ReviewSchema],
  billingInfo: {
    stripeToken: String,
    lastFour: Number,
    cardType: String
  },
  transactions: [{ type: Schema.Types.ObjectId, ref: 'Transaction'}]
});

/**
 * Virtuals
 */
UserSchema
  .virtual('password')
  .set(function(password) {
    this._password = password;
    this.salt = this.makeSalt();
    this.hashedPassword = this.encryptPassword(password);
  })
  .get(function() {
    return this._password;
  });

// Public profile information
UserSchema
  .virtual('profile')
  .get(function() {
    return {
      'firstName': this.firstName,
      'lastName': this.lastName,
      'userName': this.userName,
      'profilePicture': this.profilePicture,
      'description': this.description,
      'blog': this.blog
    };
  });

// Non-sensitive info we'll be putting in the token
UserSchema
  .virtual('token')
  .get(function() {
    return {
      '_id': this._id,
      'role': this.role
    };
  });

/**
 * Validations
 */
// Validate empty username
UserSchema
  .path('userName')
  .validate(function(userName) {
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return userName.length;
  }, 'Username cannot be blank');

// Validate empty email
UserSchema
  .path('email')
  .validate(function(email) {
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return email.length;
  }, 'Email cannot be blank');

// Validate empty password
UserSchema
  .path('hashedPassword')
  .validate(function(hashedPassword) {
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return hashedPassword.length;
  }, 'Password cannot be blank');

// Validate username is not taken
UserSchema
  .path('userName')
  .validate(function(value, respond) {
    var self = this;
    this.constructor.findOne({userName: value}, function(err, user) {
      if(err) throw err;
      if(user) {
        if(self.id === user.id) return respond(true);
        return respond(false);
      }
      respond(true);
    });
}, 'The specified username is already in use.');

// Validate email is not taken
UserSchema
  .path('email')
  .validate(function(value, respond) {
    var self = this;
    this.constructor.findOne({email: value}, function(err, user) {
      if(err) throw err;
      if(user) {
        if(self.id === user.id) return respond(true);
        return respond(false);
      }
      respond(true);
    });
}, 'The specified email address is already in use.');

var validatePresenceOf = function(value) {
  return value && value.length;
};

/**
 * Pre-save hook
 */
UserSchema
  .pre('save', function(next) {
    if (!this.isNew) return next();

    if (!validatePresenceOf(this.hashedPassword) && authTypes.indexOf(this.provider) === -1)
      next(new Error('Invalid password'));
    else
      next();
  });

var objIndexSearch = function(arr, obj, prop) {
    return _.findIndex(arr, function(item) {
        return item[prop].toString() === obj[prop].toString();
    });
};

/**
 * Methods
 */
UserSchema.methods = {
  /**
   * Authenticate - check if the passwords are the same
   *
   * @param {String} plainText
   * @return {Boolean}
   * @api public
   */
  authenticate: function(plainText) {
    return this.encryptPassword(plainText) === this.hashedPassword;
  },

  /**
   * Make salt
   *
   * @return {String}
   * @api public
   */
  makeSalt: function() {
    return crypto.randomBytes(16).toString('base64');
  },

  /**
   * Encrypt password
   *
   * @param {String} password
   * @return {String}
   * @api public
   */
  encryptPassword: function(password) {
    if (!password || !this.salt) return '';
    var salt = new Buffer(this.salt, 'base64');
    return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64');
  },

  /**
    * Addresses
    */
  addAddress: function(address, addressType, done) {
    this[addressType + "es"].addToSet(address);
    return this.save(done);
  },

  editAddress: function(address, addressType, done) {
    var indexToEdit = objIndexSearch(this[addressType + "es"], address, '_id');

    this[addressType + "es"].set(indexToEdit, address);
    return this.save(done);
  },

  makeAddressPrimary: function(address, addressType, done) {
    var indexToRemove = objIndexSearch(this[addressType + "es"], address, '_id');

    var removedAddress = this[addressType + "es"].splice(indexToRemove, 1)[0];

    this[addressType + "es"].unshift(removedAddress);
    return this.save(done);
  },

  removeAddress: function(address, addressType, done) {
    this[addressType + "es"].id(address._id).remove();
    return this.save(done);
  },

  /**
    * Reviews
    */
  addReview: function(user, review, done) {
    return this.model('User')
        .findByIdAndUpdate(user._id, {
            $addToSet: {
                reviews: _.assign({
                    reviewer: this._id
                }, review)
            }
        }, done);
  },

  editReview: function(user, review, done) {
    return this.model('User')
        .findOneAndUpdate({
            _id: user._id,
            "reviews.reviewer": this._id,
            "reviews._id": review._id
        }, {
            $set: {
                "reviews.$": review
            }
        }, done);
  },

  removeReview: function(user, review, done) {
    return this.model('User')
        .findByIdAndUpdate(user._id, {
            $pull: {
                reviews: {
                    reviewer: this._id,
                    _id: review._id
                }
            }
        }, done);
  },

  /**
    * Followers
    */
  follow: function(user, done) {
    var self = this;
    this.following.addToSet(user._id);
    return this.save(function(err, currentUser) {
        if (err) return done(err);

        self.model('User')
            .findByIdAndUpdate(user._id, {
                $addToSet: { followers: self._id }
            }, function(err, user) {
                done(err, currentUser);
            });
    });
  },

  unFollow: function(user, done) {
    var self = this;
    this.following.pull(user._id);
    return this.save(function(err, currentUser) {
        if (err) return done(err);

        self.model('User')
            .findByIdAndUpdate(user._id, {
                $pull: { followers: self._id }
            }, function(err, user) {
                done(err, currentUser);
            });
    });
  },

  /**
    * Like
    */
  like: function(item, done) {
    this.likes.addToSet(item._id);
    return this.save(done);
  },

  unLike: function(item, done) {
    this.likes.pull(item._id);
    return this.save(done);
  }
};

/**
 * Plugins
 */
UserSchema.plugin(deepPopulate);

module.exports = mongoose.model('User', UserSchema);

It didnt throw any error, but the path, which is item.seller becomes null instead of being populated

Exegetech commented 9 years ago

So basically, UserSchema has property items: [ { type: Schema.Types.ObjectId, ref: 'Item'} ] and ItemSchema has a property seller: [ { type: Schema.Types.ObjectId, ref: 'User'} ], and those two files are in separate files.

Exegetech commented 9 years ago

I made a repo example, please take a look.

https://github.com/christiansakai/deep-populate-test

Exegetech commented 9 years ago

I think I know what the bug is.

It does well with other deepPopulate as long as it does not refer back to the parent object. So in this code

var mongoose = require('mongoose');
var User = require('./user.model.js');
var Item = require('./item.model.js');
var Comment = require('./comment.model.js');
var util = require('util');

mongoose.connect('mongodb://localhost/deep-populate');

var userOne = new User({
    userName: 'userOne'
});

var itemOne = new Item({
    itemName: 'itemOne',
    seller: userOne._id
});

var commentOne = new Comment({
    commentName: 'commentOne'
});

Item.find({}).remove(function() {
    User.find({}).remove(function() {
        Comment.find({}).remove(function() {
            commentOne.save(function(err, comment) {
                itemOne.comments.addToSet(comment._id);
                itemOne.save(function(err, item) {
                    userOne.items.addToSet(itemOne._id);
                    userOne.save(function(err, user) {

                        User
                            .findById(userOne._id)
                            .deepPopulate('items.seller items.comments')
                            .exec(function(err, user) {
                                console.log(JSON.stringify(user));
                        });
                    });
                });
            });
        });
    });
});

This is the result

{
    "_id": "551156801e0b71782de10180",
    "userName": "userOne",
    "__v": 0,
    "items": [{
        "_id": "551156801e0b71782de10181",
        "itemName": "itemOne",
        "seller": null,
        "__v": 0,
        "comments": [{
            "_id": "551156801e0b71782de10182",
            "commentName": "commentOne",
            "__v": 0
        }]
    }]
}

the seller field is null while the comments field is populated

buunguyen commented 9 years ago

Fixed in 1.0.2

Exegetech commented 9 years ago

Thanks!

jimmyyao88 commented 9 years ago

I got this error too.... add the code in schema can solve ur problem: ModelSchema.methods={ deepPopulate:function(){ deepPopulate() } }

jimmyyao88 commented 9 years ago

@christiansakai

buunguyen commented 9 years ago

@jimmyyao88 if you're using v2.x, make sure you pass a mongoose instance, i.e. `require('mongoose-deep-populate')(mongoose). There's no need to add the code you showed.

jimmyyao88 commented 9 years ago

Thanks ! I did what u said ,but it turns the error: Error: Plugin was not installed , BUT my method can solve it ,I dont no y ,hahahha

ijames07 commented 9 years ago

Same as @jimmyyao88 , without note in methods throws Error: Plugin was not installed.

buunguyen commented 9 years ago

@jimmyyao88 @ijames07 please add a failed unit test case or show an executable non-working code.

ijames07 commented 9 years ago

151 passing (3s)

buunguyen commented 9 years ago

151 passing (3s)

All passed, what did you try to say?

ijames07 commented 9 years ago

I don't know unit testing, I just copied out result from it. This is my model causing troubles:

// USER.js - how is defined, if needed I will update it
"use strict";

var mongoose = require("mongoose"),
    Schema = mongoose.Schema,
var deepPopulate = require('mongoose-deep-populate')(mongoose);

var userSchema = Schema({
    warehouse: { type: Schema.Types.ObjectId, ref: "warehouse" },
...
});

userSchema.plugin(deepPopulate);

userSchema.methods = {
 ...
};

var User = mongoose.model("user", userSchema);

And there it throws error:

// PASSPORT.js  - line where it throws error
var User = require("mongoose").model("user");
    passport.use(new LocalStrategy(
        function(username, password, done) {
            User.findOne({ username: username })
                .deepPopulate("warehouse warehouse_level" +
                " warehouse_level.carrot warehouse_level.wheat" +
                " warehouse_level.corn warehouse_level.hay" +
                " warehouse_level.farm warehouse_level.ranch")
                .exec(function(err, u) {
                    if (u && u.authenticate(password)) {
                        var bu = {
                            _id: u._id,
                            username: u.username,
                            roles: u.roles,
                            warehouse: u.warehouse,
                            warehouse_level: u.warehouse_level
                        };
                        return done(null, bu);
                    } else {
                        return done(null, false);
                    }
            });
        }
    ));

// AUTH.js - line where is error (calling this function causes it) 
    var auth = passport.authenticate("local", function (err, user) {
        if (err) { return next(err); }
        if (!user) { res.send({ success: false }); }
        req.logIn(user, function (err) {
            if (err) { return next(err); }
            res.send({ success: true, user: user });
        });
    });

Full error code:

Error: Plugin was not installed
    at Query.deepPopulate (C:\Users\James\Desktop\zoo\node_modules\mongoose-deep-populate\lib\plugin.js:29:13)
    at Strategy._verify (C:\Users\James\Desktop\zoo\app\config\passport.js:12:6)
    at Strategy.authenticate (C:\Users\James\Desktop\zoo\node_modules\passport-local\lib\strategy.js:90:12)
    at attempt (C:\Users\James\Desktop\zoo\node_modules\passport\lib\middleware\authenticate.js:341:16)
    at authenticate (C:\Users\James\Desktop\zoo\node_modules\passport\lib\middleware\authenticate.js:342:7)
    at exports.authenticate (C:\Users\James\Desktop\zoo\app\config\auth.js:18:2)
    at Layer.handle [as handle_request] (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\route.js:131:13)
    at Route.dispatch (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\James\Desktop\zoo\node_modules\express\lib\router\index.js:277:22
    at Function.process_params (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\index.js:330:12)
    at next (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\index.js:271:10)
    at serveStatic (C:\Users\James\Desktop\zoo\node_modules\express\node_modules\serve-static\index.js:74:16)
    at Layer.handle [as handle_request] (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\James\Desktop\zoo\node_modules\express\lib\router\index.js:312:13)
ansgarm commented 9 years ago

Had this issue myself. The deepPopulate plugin integrates itself into the methods of the Model. Hence calling it after

userSchema.methods = {
 ...
};

will solve your problem. If you call it first, the deepPopulate method will get overwritten..

giovannic commented 8 years ago

@ansgarm Thanks, this solved it for me

jpidelatorre commented 8 years ago

@ansgarm Thank you so much, you saved me. This should be documented.

backend-stunntech commented 6 years ago

Thanks, @ansgarm, you helped me solve the problem.