Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongoose.js: _id of embedded document

I am trying to save a task to a list of tasks with mongoose and MongoDB. I want to save it redundantly in the tasks collection and in the corresponding list document as embedded document.

It works fine but one little thing: The list's embedded documents don't have their objectIds. But I need them in order to connect them logically with the documents in the tasks-collection.

My Schemas:

var TaskSchema = new Schema({
    _id: ObjectId,
    title: String,
    list: ObjectId

});

var Task = mongoose.model('task', TaskSchema);

var ListSchema = new Schema({
    _id: ObjectId,
    title: String,
    tasks: [Task.schema]
});

var List = mongoose.model('list', ListSchema);

My controller/router:

app.post('/lists/:list_id/tasks', function(req, res) {

        var listId = req.params.list_id;   

        // 1. Save the new task into the tasks-collection.

        var newTask = new Task();
        newTask.title = req.body.title;
        newTask.list = listId; 

        console.log('TaskId:' + newTask._id);  // Returns undefined on the console!!!

        newTask.save(); // Works fine!

        // 2. Add the new task to the coresponding list.

        list.findById(listId, function(err, doc){

            doc.tasks.push(newTask);

            doc.save();  // Saves the new task in the list but WITHOUT its objectId

            });

        res.redirect('/lists/' + listId)

});

Can I use mongoose a different way to achieve that? Or do I have to save the task and then query it before saving it in the list?

Thank you for advise :-)

like image 954
Sven Avatar asked Dec 27 '22 23:12

Sven


1 Answers

I solved it by using an awesome feature called populate!

Also dtryon was right: You don't need to declare your _id ObjectIds in your models, they are getting added anyways. And you have to nest this stuff because your task is being saved asyncronously so you must get sure that runs before the other stuff.

Here is the solution:

Schemas:

var TaskSchema = new Schema({
    title: String,
    list: { type: Schema.ObjectId, ref: 'list' }

});

var Task = mongoose.model('task', TaskSchema);

var ListSchema = new Schema({
    title: String,
    tasks: [{ type: Schema.ObjectId, ref: 'task' }]
});

var List = mongoose.model('list', ListSchema);

Controller/router:

app.post('/lists/:list_id/tasks', function(req, res) {

    var listId = req.params.list_id;   

    var newTask = new Task();
    newTask.title = req.body.title;
    newTask.list = listId; 


    // WHEN SAVING, WRAP THE REST OF THE CODE

    newTask.save(function (err){
       if (err) {
            console.log('error saving new task');
            console.log(err);
        } else {
            console.log('new task saved successfully'); 

            list.findById(listId), function(err, doc){

                doc.tasks.push(newTask);

                doc.save(function (err){
                    if (err) {
                    console.log('error adding new task to list');
                    console.log(err);
                    } else {

                    console.log('new task saved successfully'); 
                    res.redirect('/lists/' + listId);

                    }  
                });
            });
        });
    });
});

Now it references correctly and with the populate feature you can access the entries very comfortably. Works like charm :-)

like image 186
Sven Avatar answered Jan 05 '23 06:01

Sven