0

This REST endpoint updates the favourites list in my database, by removing qname from user.favourites.

My problem is that although updatedUser.favourites is correct at the end of the code, this is not actually being persisted in the database (similar code to add a qname on a separate endpoint do work). I'm sure this is a silly mistake, but what I've written feels intuitively correct.

exports.remQname = function (req, res, next) {
    var userId = req.user.id;
    var qname = req.params.qname;

    console.log('addQname %s %s', userId, qname);
    User.findOne({
        _id: userId
    }, function(err, user) {
        if (err) return next(err);
        if (!user) return res.json(401);

        console.log(user);

        // if the qname already in list, remove it, otherwise add it
        var favourites = user.favourites;
        var matches = _.remove(favourites, function (f) {
            return f == qname
        });
        console.log('Matches: %s %s', matches, favourites);

        user.favourites = favourites;
        user.save(function(err, updatedUser){
            if (err) throw err;
            console.log(updatedUser);  // correct info, but does not reflect database content
            res.status(200).send(updatedUser.favourites);
        });
    });     
};

Here is my Schema

var UserSchema   = new Schema({
    email: String,
    password: String,
    token: String,
    role: {type: String, default: 'user'},
    favourites: Array
});

module.exports = mongoose.model('User', UserSchema);
4
  • 1
    That doesn't sound very RESTful. "..Either adds or deletes...". An API should expectedly do exactly what it describes. So in REST terminology you POST to "add", PUT to change, DELETE to delete and GET to retrieve. I don't like the sound of an API endpoint that "flips a coin" to decide what happens. There is a much better way to code this. Particularly when you accept what I just said in that different verbs lead to different actions, rather than "inspection" for a "state change". Commented Mar 7, 2015 at 10:41
  • Fair comment, and something I will need to change. But I would still use the code above to provide a remove route, and its not going to work Commented Mar 7, 2015 at 10:43
  • See that's where you lost me. I don't want to come across this route one day and find out it either "adds or removes" depending on what is there. So I just won't be the person to help you do something I disagree with. Commented Mar 7, 2015 at 10:50
  • @NeilLunn: No problem. Have changed question to avoid your concern Commented Mar 7, 2015 at 10:55

2 Answers 2

2

You can directly remove all instances of a specific value from an array field using $pull, so it would be more efficient to let MongoDB do the work rather than trying to manipulate the array yourself.

User.update({_id: userId},
            {$pull: {favourites: qname}},
            function(err, numberAffected, raw) { ... });

I'd also suggest changing your definition of favourites in the schema to be [String] instead of just Array if it does contain an array of strings.

Sign up to request clarification or add additional context in comments.

Comments

1

It had something to do with lodash - this works instead

    var newFavs = _.reject(user.favourites, function (f) {
        return f == qname
    });

    console.log('Favourites - Old: %s New: %s', user.favourites, newFavs);

    // delete user.favourites;
    user.favourites = newFavs;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.