简体   繁体   中英

How to add a subdocument in a mongoose schema

I am trying to create a subdocument in a mongoose schema from node.js/Express.

I have two schemas: Member and Address

Member.js

// app/models/member.js

// load mongoose since we need it to define a model
var mongoose = require('mongoose'),
  Schema = mongoose.Schema

var Address = require('./address');

var MemberSchema = Schema({
  FName : String,
  LName : String,
  address : [Address],
  phone : {
    type : String,
    number : String
  },
  email: String,
  gender: String,
  DOB: Date,
  rank : {
    level : String,
    updated: { type: Date, default: Date.now }
  },
  Awards : {
    personal : Boolean,
    award : { type : Schema.Types.ObjectId, ref : 'Award' },
    granted: { type: Date, default: Date.now }
  }
});


module.exports = mongoose.model('Member', MemberSchema);

Address.js

// app/models/address.js

// load mongoose since we need it to define a model
var mongoose = require('mongoose'),
  Schema = mongoose.Schema

var AddressSchema = Schema({
  type : String,
  street1 : String,
  street2 : String,
  City : String,
  State : String,
  Zip : Number,
  Lat : Number,
  Lng : Number
});


module.exports = mongoose.model('Address', AddressSchema);

My Intent is to create a member, then add an address. The POST call for member works. However, when executing a POST call for address, it fails saying undefined, and I cannot find the location of the error. I am hoping to find out how better to add addresses to my member schema.

routes.js

  app.route('/api/member')

    .get(function(req, res) { ...

    .post(function(req, res) {
      var new_member = new member();
      new_member.FName = req.body.fname;
      new_member.LName = req.body.lname;
      new_member.DOB = req.body.DOB;
      new_member.email = req.body.email;
      new_member.gender = req.body.gender;

      new_member.save(function(err) {
          if (err)
              res.send(err);

          res.json({ message: 'Member Created!' });
      });
    });

  app.route('/api/member/:member_id/address')

    .post(function(req, res) {
      member.findById(req.params.member_id, function(err, member) {
        if (err)
          return (err);

        new_address = new address();
        new_address.type = req.body.atype;
        new_address.street1 = req.body.street1;
        new_address.street2 = req.body.street2;
        new_address.City = req.body.City;
        new_address.State = req.body.State;
        new_address.Zip = req.body.Zip;
        new_address.Lat = req.body.Lat;
        new_address.Lng = req.body.Lng;
        console.log(new_address);

        member.address.push(new_address);

        res.json({ message : "Address added!!" });

      });
    });

Like I said, adding Member is easy. Adding an address results in the below error:

/Users/arcee123/projects/MCARS/node_modules/mongoose/lib/utils.js:419
        throw err;
              ^
TypeError: undefined is not a function
    at Array.MongooseArray._cast (/Users/arcee123/projects/MCARS/node_modules/mongoose/lib/types/array.js:108:30)
    at Object.map (native)
    at Array.MongooseArray.push (/Users/arcee123/projects/MCARS/node_modules/mongoose/lib/types/array.js:262:23)
    at Promise.<anonymous> (/Users/arcee123/projects/MCARS/app/routes.js:108:24)
    at Promise.<anonymous> (/Users/arcee123/projects/MCARS/node_modules/mongoose/node_modules/mpromise/lib/promise.js:162:8)
    at Promise.emit (events.js:107:17)
    at Promise.emit (/Users/arcee123/projects/MCARS/node_modules/mongoose/node_modules/mpromise/lib/promise.js:79:38)
    at Promise.fulfill (/Users/arcee123/projects/MCARS/node_modules/mongoose/node_modules/mpromise/lib/promise.js:92:20)
    at /Users/arcee123/projects/MCARS/node_modules/mongoose/lib/query.js:1833:13
    at model.Document.init (/Users/arcee123/projects/MCARS/node_modules/mongoose/lib/document.js:251:11)
15 Jun 15:45:49 - [nodemon] app crashed - waiting for file changes before starting...

where am I going wrong? Thanks

UPDATE 1: The .post call for the address push now looks like this:

.post(function(req, res) {
  member.findById(req.params.member_id, function(err, member) {
    if (err)
      return (err);

    new_address = new address();
    new_address.type = req.body.atype;
    new_address.street1 = req.body.street1;
    new_address.street2 = req.body.street2;
    new_address.City = req.body.City;
    new_address.State = req.body.State;
    new_address.Zip = req.body.Zip;
    new_address.Lat = req.body.Lat;
    new_address.Lng = req.body.Lng;
    console.log(new_address);

    if(member.address === undefined){
        member.address.push(new_address);
    }
    else{
         member.address = [new_address];
    }

    member.save(function(err) {
        if (err)
            res.send(err);

        res.json({ message: 'Address created!!!' });
    });

  });

});

Since the address field is not required by Mongoose when you retrieve the Model from the database the field just won't be defined. Thus you won't be able to add an address field. You should check to see if it exists

if(member.address !== undefined){
    member.address.push(new_address);
}
else{
     member.address = [new_address];
}

Edit: Also you will then have to save it back into the database. (You can also look at the update function)

Just as @Treesrule14 said, if you do not have an initial member.address, you will need to set it to be [new_address]. You are saving your document in the first route, but not the second route. In the second route, you are just returning the document without saving it.

If you always want an address field (even if it is empty), you can change your address field in the member schema to be address: {type: [address], default:[]} . This will make sure an empty array will beset by default, and you can push to it or read it's length without worrying about it being undefined.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM