3

I have a nested schema defined with mongoose:

//application.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Category = require('./category.js');

var Application = new Schema({
    title : String,
    cats : [Category]
});

Application.virtual('app_id').get(function() {
    return this._id;
});

module.exports = mongoose.model('Application', Application);

and

//account.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var Application = require('./application.js');

var Account = new Schema({
    username: String,
    password: String,
    apps: [Application]
});

Account.plugin(passportLocalMongoose);

module.exports = mongoose.model('Account', Account);

Now if I try to push to apps which is an array in account like this:

app.post('/application', function(req,res){
  var name = req.user.username;
  var newApp = new Application();
  newApp.title = req.body.title;
  console.log(newApp);

  Account.findOneAndUpdate({username : name},
    {$push: {apps: newApp}},
    {safe: true, upsert: true},
    function(err, model){
      if (err){
        console.log(model);
        console.error("ERROR: ", err);
        res.status(500).send(err);
     }else{
       res.status(200).send({"status":"ok"});
     }
    }
  );
});

I get the error:

{ title: 'dogs', _id: 564f1d1444f30e0d13e84e7b, cats: [] }
undefined
ERROR:  { [CastError: Cast to undefined failed for value "[object Object]" at path "apps"]
  message: 'Cast to undefined failed for value "[object Object]" at path "apps"',
  name: 'CastError',
  type: undefined,
  value: [{"title":"dogs","_id":"564f1d1444f30e0d13e84e7b","cats":[]}],
  path: 'apps' }

what am I doing wrong?

EDIT:

Found the answer in this question Practically I need to import the schema not the object

//account.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var ApplicationSchema = require('./application.js').schema; //<-- .schema was added

var Account = new Schema({
    username: String,
    password: String,
    apps: [ApplicationSchema]
});

Account.plugin(passportLocalMongoose);

module.exports = mongoose.model('Account', Account);
Community
  • 1
  • 1
Sanandrea
  • 2,112
  • 1
  • 27
  • 45

1 Answers1

5

To save the Application reference within the Account model's apps embedded document field, push the _id value in the Application model's callback on save:

account.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var Application = require('./application.js');

var Account = new Schema({
    username: String,
    password: String,
    apps: [{type: Schema.Types.ObjectId, ref: 'Application'}]
});

Account.plugin(passportLocalMongoose);
module.exports = mongoose.model('Account', Account);

app.js

app.post('/application', function(req, res){
    var name = req.user.username;
    var newApp = new Application({
        title: req.body.title
    }); 
    console.log(newApp);

    newApp.save(function (err){
        if (err) return handleError(err);

        Account.findOne({ username: name }, function (err, doc){
            if (err) return handleError(err);
            doc.apps.push(newApp._id);        
            doc.save();
            res.status(200).send({"status":"ok"});
        });
    });
});

Or using promises as:

const handleError = err => console.error(err);

app.post('/application', (req, res) => {
    const name = req.user.username;
    const newApp = new Application({
        title: req.body.title
    }); 

    newApp.save().then(result => (
        Account.findOneAndUpdate(
            { "username": name },
            { "$push": { "apps": result._id } }
        )
    )
    .then(result => res.status(200).send({"status":"ok"}))
    .catch(handleError);        
});
chridam
  • 100,957
  • 23
  • 236
  • 235
  • 1
    yes I tried this too and it works! See my edit please. I now realised that was declaring that field as array of ids instead of actual objects. I will accept answer even though I was trying to do a different thing. thank you – Sanandrea Nov 20 '15 at 14:20
  • @Sanandrea No worries, glad it all worked out for you in the end :) – chridam Nov 20 '15 at 14:24
  • I noticed that due to some code mixes I hadn't realised that in order for your suggestion to work I had to change: apps: [ObjectId] in account.js. where ObjectId is var ObjectId = Schema.ObjectId. So please update your answer. – Sanandrea Nov 20 '15 at 14:42
  • @Sanandrea Yea, noticed that too, initially thought you had embedded the refs as `apps: [{type: Schema.Types.ObjectId, ref: 'Application'}]`, in which case the answer would suffice. – chridam Nov 20 '15 at 14:45