-1

My activity model has a property which is a reference to an ObjectId in the units table. The method works fine, in my opinion, as console logging unit.name logs correct name and also never hits the catch clause so there is no error in retrieval of the name, so I assume that it is being returned as well.

Unfortunately, assuming activity is an instance of activities, calling activity.unit_id in my view returns undefined and my view shows undefined. All other properties are being printed properly:

enter image description here

My activity model's schema:

var activitySchema = new Schema({
    name: {
        type: String, 
        required: true
    },
    description: {
        type: String,
        required: true
    },
    pointsPerUnit: {
        type: Number,
        required: true
    },
    unit_id: {
        type: Schema.Types.ObjectId, 
        ref: 'Unit',
        get: function(unit_id) {
            Unit.findById(unit_id).then((unit) => {
                console.log(unit.name)
                return unit.name
            }).catch((e) => console.log(e));
        }
    }
}); 

Here is what I am calling in my .pug file:

h2 All Activities

each activity in activities
    p= "Name: " + activity.name
    p= "Description: " + activity.description
    p= "Points Per Unit of Excersise: " + activity.pointsPerUnit
    p= "Unit: " + activity.unit_id
    hr

I am also explicity logging mongoose queries to my console. Here's the execution from mongoose, which is also correct:

Mongoose: units.findOne({ _id: ObjectId("592679205a7b0e0c8fe7f47f") }, { fields: {} })
Mongoose: units.findOne({ _id: ObjectId("592679205a7b0e0c8fe7f47f") }, { fields: {} })

Here is the controller code for the route:

/* GET users listing. */
router.get('/new', function(req, res, next) {
    Activity.find({}).then((activities) => {
        res.render('activities/new', {activities});
    }); 
});

Have spent two hours on this issue with no luck! Any help is appreciated.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
Govind Rai
  • 14,406
  • 9
  • 72
  • 83
  • 1
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Lennholm May 25 '17 at 23:36
  • I would second that notion that this is indeed a duplicate, but the question does not even display the controller code for the request. So it's likely the cause but unclear without the necessary code. – Neil Lunn May 25 '17 at 23:50
  • @NeilLunn See updated answer. This is all the relevant code I have in my project. The view renders, the route works, every field except the unit_id field displays properly. It's just that I store a foreign key to a unit and upon pulling the record from the activity I want the name of the unit and not the unit id. – Govind Rai May 25 '17 at 23:52
  • Then are any results returning from `Activity.find({})` at all? Add in a `console.log()` or something to check. If empty then make sure you are actually connecting to the correct database and have the correct collection name.Noting that mongoose is expecting a collection named `"activities"` by default unless you explicitly told it otherwise. – Neil Lunn May 25 '17 at 23:57
  • @NeilLunn Yes, results are returned correctly. See the first image in my question. Its just that one property in each record is incorrect. It renders undefined. When i call `activity.unit_id` it console.log() the correct unit name but view renders undefined. – Govind Rai May 25 '17 at 23:58
  • Okay. I see it now.The `get` function in the schema is not how you do this. You use the `.populate()` method instead. Modern mongoose even supports this with "virtual fields". See the documentation. But as a weird variant of the initial duplicate, you are trying to "pass in" an async method as the "getter". Which basically has the same results in consequence. – Neil Lunn May 26 '17 at 00:07
  • OMG. that's it! You are a god, @NeilLunn. Going from a traditional rdbms to MongoDB has been quite a challenge.. too bad teh question has a -1 :( – Govind Rai May 26 '17 at 00:18

1 Answers1

1

You are trying to define a "getter" in your schema using an async method. Instead of doing this you should be calling .populate() in the controller:

activity schema

var activitySchema = new Schema({
    name: {
        type: String, 
        required: true
    },
    description: {
        type: String,
        required: true
    },
    pointsPerUnit: {
        type: Number,
        required: true
    },
    unit_id: {
        type: Schema.Types.ObjectId, 
        ref: 'Unit',
    }
});

controller code

/* GET users listing. */
router.get('/new', function(req, res, next) {
    Activity.find({}).populate('unit_id').then((activities) => {
        res.render('activities/new', {activities});
    }); 
});

This makes sure the objects from Unit are resolved before calling the template.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317