RangeError:Nodejs + Mongoose构建的API

时间:2017-06-25 20:04:08

标签: node.js api mongoose model

我在使用mongoose和Nodejs时收到超出最大调用堆栈大小的错误。这是错误

RangeError: Maximum call stack size exceeded
    at model.Document.$toObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2045:24)
    at model.Document.toJSON (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2362:15)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:252:18)
    at cloneArray (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:362:14)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:247:12)
    at cloneObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:343:13)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:260:16)
    at model.Document.$toObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2092:13)

我相信这意味着我在某处造成无限循环,但我不确定导致错误的原因。路线工作正常,然后我将mongoose-autopopulate插件添加到应用程序。使用令牌正确发送POST到我的驱动器路径后,我收到此错误。没有记录任何内容,服务器停止。

以下是我在drive.js

中的路线示例
   router.post('/', function(req, res, next){
  var decoded = jwt.decode(req.query.token);
  User.findById(decoded.user._id, function(err, user){
    if (err) {
      return res.status(500).json({
        title: 'There was a server error',
        error: err
      });
    }
    var drive = new Drive({
      startAddress: req.body.startAddress,
      endAddress: req.body.endAddress,
      tripDate: req.body.tripDate,
      tripHour: req.body.tripHour,
      price: req.body.price,
      numberOfPassengers: req.body.numberOfPassengers,
      user: user
    });
    drive.save(function (err, result) {
      if(err) {
        return res.status(500).json({
          title: 'There was an error saving the drive collection',
          error: err
        });
      }
      user.drives.push(result);
      user.save();
      res.status(201).json({
        message: 'Drive saved',
        obj: result
      });
    });
  });
});

这是相关模型

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = require('./user.model');
var Trip = require('./trip.model');
var autoPopulate = require('mongoose-autopopulate');



var driveSchema = new Schema({
  startAddress: {type: String, required: true, lowercase: true},
  endAddress: {type: String, required: true, lowercase: true},
  tripDate: {type: Date, required: true},
  tripHour: {type: String, required: true},
  price: {type: Number, required: true},
  numberOfPassengers: {type: Number, required: true},
  trip: {type: Schema.Types.ObjectId, ref: 'Trip', autopopulate: true},
  user: {type: Schema.Types.ObjectId, ref: 'User', autopopulate: true}
});

driveSchema.post('remove', function(drive) {
  User.findById(drive.user, function(err, user) {
    user.drives.pull(drive);
    user.save();
  });
});

driveSchema.plugin(autoPopulate);


module.exports = mongoose.model('Drive', driveSchema);

我的所有模型都遵循相同的方法和查询。有什么具体的我做错了吗?我查了一下,似乎我可以调用一个实例而不是JSON来破坏代码,但我没有经验足以识别该实例的位置,或者是什么导致重新调用的调用为.find()或.where()我正在使用的是打破它。

以下是我的其他型号

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var autopopulate = require('mongoose-autopopulate');

var tripSchema = new Schema({
  tripActivated: {type: Boolean},
  tripCompleted: {type: Boolean},
  driver: {type: Schema.Types.ObjectId, ref: 'Drive', autopopulate: true},
  riders: [{type: Schema.Types.ObjectId, ref: 'Ride', autopopulate: true}],
  comments: [{type: Schema.Types.ObjectId, ref: 'Comment', autopopulate: true}]
});

tripSchema.post('remove', function(trip) {
  User.findById(trip.driver.user, function(err, user) {
    user.trips.pull(trip);
    user.save();
  });
});


// tripSchema.post('remove', function(trip) {
//   User.findById(trip.riders.user, function(err, user) {
//     user.trips.pull(trip);
//     user.save();
//   });
// });

tripSchema.plugin(autopopulate);

module.exports = mongoose.model('Trip', tripSchema);


//// NEW MODEL

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = require('./user.model');
var Trip = require('./trip.model');
var autoPopulate = require('mongoose-autopopulate');



var rideSchema = new Schema({
  startAddress: {type: String, required: true, lowercase: true},
  endAddress: {type: String, required: true, lowercase: true},
  tripDate: {type: Date, required: true},
  tripHour: {type: String, required: true},
  numberOfPassengers: {type: Number, required: true},
  trip: {type: Schema.Types.ObjectId, ref: 'Trip', autopopulate: true},
  user: {type: Schema.Types.ObjectId, ref: 'User', autopopulate: true}
});

rideSchema.post('remove', function(ride) {
  User.findById(ride.user, function(err, user) {
    user.rides.pull(ride);
    user.save();
  });
});

rideSchema.plugin(autoPopulate);


module.exports = mongoose.model('Ride', rideSchema);


////// NEW MODEL

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = require('./user.model');
var autoPopulate = require('mongoose-autopopulate');


var requestSchema = new Schema({
  typeOfRequest: {type: String, required: true},
  driver: {type: Schema.Types.ObjectId, ref: 'Drive', autopopulate: true},
  rider: {type: Schema.Types.ObjectId, ref: 'Ride', autopopulate: true}
});

requestSchema.post('remove', function(request) {
  User.findById(request.user, function(err, user) {
    user.requests.pull(request);
    user.save();
  });
});

requestSchema.plugin(autoPopulate);


module.exports = mongoose.model('Request', requestSchema);

////新模型

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var autoPopulate = require('mongoose-autopopulate');


var User = require('./user.model');

var messageSchema = new Schema ({
  content: {type: String, required: true},
  receiver: {type: Schema.Types.ObjectId, ref: 'User', autopopulate: true },
  user: {type: Schema.Types.ObjectId, ref: 'User', autopopulate: true}
});

messageSchema.post('remove', function(message) {
  User.findById(message.user, function(err, user) {
    user.messages.pull(message);
    user.save();
  });
});

messageSchema.plugin(autoPopulate);


module.exports = mongoose.model('Message', messageSchema);

深入探讨后,我的错误似乎源于此节点,该代码在node_modules中的mongoose源代码中加注

Document.prototype.$toObject = function(options, json) {
  ***var defaultOptions = {
    transform: true,
    json: json,
    retainKeyOrder: this.schema.options.retainKeyOrder,
    flattenDecimals: true
  };***

  // _isNested will only be true if this is not the top level document, we
  // should never depopulate
  if (options && options.depopulate && options._isNested && this.$__.wasPopulated) {
    // populated paths that we set to a document
    return clone(this._id, options);
  }

  // When internally saving this document we always pass options,
  // bypassing the custom schema options.
  if (!(options && utils.getFunctionName(options.constructor) === 'Object') ||
      (options && options._useSchemaOptions)) {
    if (json) {
      options = this.schema.options.toJSON ?
        clone(this.schema.options.toJSON) :
        {};
      options.json = true;
      options._useSchemaOptions = true;
    } else {
      options = this.schema.options.toObject ?
        clone(this.schema.options.toObject) :
        {};
      options.json = false;
      options._useSchemaOptions = true;
    }
  }

  for (var key in defaultOptions) {
    if (options[key] === undefined) {
      options[key] = defaultOptions[key];
    }
  }

  ('minimize' in options) || (options.minimize = this.schema.options.minimize);

  // remember the root transform function
  // to save it from being overwritten by sub-transform functions
  var originalTransform = options.transform;

  options._isNested = true;

  var ret = clone(this._doc, options) || {};

  if (options.getters) {
    applyGetters(this, ret, 'paths', options);
    // applyGetters for paths will add nested empty objects;
    // if minimize is set, we need to remove them.
    if (options.minimize) {
      ret = minimize(ret) || {};
    }
  }

  if (options.virtuals || options.getters && options.virtuals !== false) {
    applyGetters(this, ret, 'virtuals', options);
  }

  if (options.versionKey === false && this.schema.options.versionKey) {
    delete ret[this.schema.options.versionKey];
  }

  var transform = options.transform;

  // In the case where a subdocument has its own transform function, we need to
  // check and see if the parent has a transform (options.transform) and if the
  // child schema has a transform (this.schema.options.toObject) In this case,
  // we need to adjust options.transform to be the child schema's transform and
  // not the parent schema's
  if (transform === true ||
      (this.schema.options.toObject && transform)) {
    var opts = options.json ? this.schema.options.toJSON : this.schema.options.toObject;

    if (opts) {
      transform = (typeof options.transform === 'function' ? options.transform : opts.transform);
    }
  } else {
    options.transform = originalTransform;
  }

  if (typeof transform === 'function') {
    var xformed = transform(this, ret, options);
    if (typeof xformed !== 'undefined') {
      ret = xformed;
    }
  }

  return ret;
};

我设置了mongoose.set('debugger',true);以获得更好的错误。当试图发布ride.js时,应用程序注册POST请求,找到userID,处理新的Ride(基于模型),将骑行插入数据库,然后立即崩溃。

这是mongoose日志的错误

Mongoose: users.ensureIndex({ email: 1 }, { unique: true, background: true })
Successfully connected to localhost:27017/atlas
Mongoose: users.findOne({ _id: ObjectId("59506e1629cdff044664f21c") }, { fields: {} })
(node:1219) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html
Mongoose: rides.insert({ startAddress: 's', endAddress: 's', tripDate: new Date("Fri, 22 Feb 2222 00:00:00 GMT"), tripHour: '8', numberOfPassengers: 2, user: ObjectId("59506e1629cdff044664f21c"), _id: ObjectId("595078cf0b46e704c3091070"), __v: 0 })
events.js:160
      throw er; // Unhandled 'error' event
      ^

RangeError: Maximum call stack size exceeded
    at model.Document.$toObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2045:24)
    at model.Document.toJSON (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2362:15)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:253:18)
    at cloneArray (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:363:14)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:247:12)
    at cloneObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:344:13)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:261:16)
    at model.Document.$toObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2092:13)
    at model.Document.toJSON (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2362:15)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:253:18)
    at cloneObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:344:13)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:261:16)
    at model.Document.$toObject (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2092:13)
    at model.Document.toJSON (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/document.js:2362:15)
    at clone (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:253:18)
    at cloneArray (/Users/joncorrin/Desktop/workspace/MEAN/atlas-web/node_modules/mongoose/lib/utils.js:363:14)

********** UPDATE

在做了一些挖掘之后,这就是打破应用程序的代码

user.drives.push(result); <----------
          user.save();

将数据插入mongodb然后当它试图推送给用户时,它会中断。知道为什么吗?我添加了我的用户模型以供参考。

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongooseUniqueValidator = require('mongoose-unique-validator');
var autoPopulate = require('mongoose-autopopulate');


    var userSchema = new Schema({
      email: {type: String, required: true, unique: true, lowercase:true},
      password: {type: String, required: true},
      profileImgUrl: {type: String},
      fName: {type: String},
      lName: {type: String},
      yearOfBirth: {type: String},
      gender: {type: String},
      ratings: [{type: Number}],
      comments: [{type: Schema.Types.ObjectId, ref: 'Comment', autopopulate: true}],
      messages: [{type: Schema.Types.ObjectId, ref: 'Message', autopopulate: true}],
      rides: [{type: Schema.Types.ObjectId, ref: 'Ride', autopopulate: true}],
      drives: [{type: Schema.Types.ObjectId, ref: 'Drive', autopopulate: true}],
      requests: [{type: Schema.Types.ObjectId, ref: 'Request', autopopulate: true}],
      trips: [{type: Schema.Types.ObjectId, ref: 'Trip', autopopulate: true}]
    });

    userSchema.plugin(mongooseUniqueValidator);
    userSchema.plugin(autoPopulate);

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

1 个答案:

答案 0 :(得分:0)

问题出在我的用户模型中。我正在使用mongoose-autopopulate插件并将autopopulate设置为其中包含用户实例的真实对象。

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongooseUniqueValidator = require('mongoose-unique-validator');
var autoPopulate = require('mongoose-autopopulate');


    var userSchema = new Schema({
      email: {type: String, required: true, unique: true, lowercase:true},
      password: {type: String, required: true},
      profileImgUrl: {type: String},
      fName: {type: String},
      lName: {type: String},
      yearOfBirth: {type: String},
      gender: {type: String},
      ratings: [{type: Number}],
      comments: [{type: Schema.Types.ObjectId, ref: 'Comment', autopopulate: true}],
      messages: [{type: Schema.Types.ObjectId, ref: 'Message', autopopulate: true}],<---------
      rides: [{type: Schema.Types.ObjectId, ref: 'Ride', autopopulate: true}],<---------
      drives: [{type: Schema.Types.ObjectId, ref: 'Drive', autopopulate: true}],<-----------
      requests: [{type: Schema.Types.ObjectId, ref: 'Request', autopopulate: true}],
      trips: [{type: Schema.Types.ObjectId, ref: 'Trip', autopopulate: true}]
    });

    userSchema.plugin(mongooseUniqueValidator);
    userSchema.plugin(autoPopulate);

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

我还在这些模型上将autopopulate设置为true。这在填充给定模型和用户模型之间调用了无限循环。

如果有人遇到此问题。不要像我一样在堆栈溢出上发布一堆代码。弄清楚你打电话回来的电话。就我而言,我在两个可以来回通信的模型上调用autopopulate。