29

I work with nodejs/express/mongoose/angularjs. I'd like to update a collection named Lists which has several properties, one of which is an array of items. In the following code, I'm pushing a new task items in the items array. Everything works fine, however the update function does not sends back the updated collection, then I must perform another query on the database. Is there a more efficient way to do this ?

The nodejs/express code :

exports.addTaskToList = function(req, res) {
    var listId = req.params.Id;
    var taskId = req.params.TaskId;
    Lists.update({_id: listId}, {$push: {items: taskId}}, {safe:true, upsert: true}, function(err, result){
        if(err) {
            console.log('Error updating todo list. ' + err);
        }
        else{
            console.log(result + ' todo list entry updated - New task added');
            Lists.findById(listId).populate('items').exec(function (err, updatedEntry) {
                if (err) {
                    console.log('Unable to retrieve todo list entry.');
                }
                res.send(JSON.stringify(updatedEntry));
            });
        }           
    });
};

Furthermore, the array items is an array of ObjectIds. Those items are in a separate schema so in a separate collection. Is it possible to push the whole object and not only its _id so that there is not another collection created ?

KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133
GuillaumeA
  • 3,493
  • 4
  • 35
  • 69
  • Consider using `findOneAndUpdate` with the `{ new: true }` option. It will perform updates and return the updated object. (Or the un-updated object with `new` set to `false`) – user Dec 15 '16 at 07:40

3 Answers3

34

use findOneAndUpdate() method and in query parameter use option as { "new": true}

return this.sessionModel
       .findOneAndUpdate({user_id: data.user_id}, {$set:{session_id: suuid}}, { "new": true})
       .exec()
       .then(data=>{
        return {
          sid: data.session_id
            }
        })
KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133
27

The update method doesn't return the updated document:

However, if we don't need the document returned in our application and merely want to update a property in the database directly, Model#update is right for us.

If you need to update and return the document, please consider one of the following options:

Traditional approach:

Lists.findById(listId, function(err, list) {
    if (err) {
        ...
    } else {
        list.items.push(taskId)
        list.save(function(err, list) {
            ...
        });
    }
});

Shorter approach:

Lists.findByIdAndUpdate(listId, {$push: {items: taskId}}, function(err, list) {
    ...
});
Diogo Cardoso
  • 21,637
  • 26
  • 100
  • 138
Mattias Farnemyhr
  • 4,148
  • 3
  • 28
  • 49
1

Regarding your last question:

Is it possible to push the whole object and not only its _id so that there is not another collection created ?

The answer is yes. You can store sub-documents within documents quite easily with Mongoose (documentation on sub-documents here). By changing your schema a little, you can just push your whole item object (not just item _id) into an array of items defined in your List schema. But you'll need to modify your schema, for example:

var itemSchema = new Schema({ 
    // Your Item schema goes here
    task: 'string'       // For example
});

var listSchema = new Schema({
    // Your list schema goes here
    listName: String,    // For example...
    items: [itemSchema]  // Finally include an array of items
});

By adding an item object to the items property of a list, and then saving that list - your new item will be persisted to the List collection. For example,

var list = new List({
    listName: "Things to do"
});

list.items.push({
    task: "Mow the lawn"
});

list.save(function(error, result) {
    if (error) // Handle error
    console.log(result.list) // Will contain your item instance
});

So when you load your list, the items property will come pre-populated with your array of items.

This is because Items will no longer persist it a separate collection. It will be persisted to the List collection as a sub-document of a List.

C Blanchard
  • 1,063
  • 9
  • 10
  • Thanks Mr. Blanchard (speak French??). I've already seen this, but I was wondering how to efficiently retrieve an item. The way I did it is very convenient as there is a generated _id and I dont want to bother with it myself. I need to explore a little more this avenue, thanks. – GuillaumeA Dec 19 '13 at 02:46
  • The doc answered my question : "Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id." – GuillaumeA Dec 19 '13 at 02:48