3
votes

I'm creating an application in Node that has some CRUD components. On one of my data objects, I have a save() method that is meant to update a record if the object has an id that is found in the collection, or upsert a new document if not. Additionally, if doing an upsert I'd like to get back the _id for the document generated by Mongo.

It seems that findAndModify would do this, and, indeed, it does return an _id value from the database. In my query clause, I am filtering by _id. If my data object doesn't have an id, Mongo correctly does an upsert, however, no matter what _id value it returns, in addition to the the keys I am setting in the update clause, it also sets the _id on the document based on what value I used in the query clause. Some code for clarity:

User.prototype.save = function(callback) {
    var that = this;

    var args = {
        'query'     : { _id: this.getId() }, //getId() returns empty string if not set
        'update'    : { $set : {
            firstName   : this.firstName,
            lastName    : this.lastName,
            email       : this.email
          //_id        : this.getId()
          // which is blank, is magically getting added due to query clause
        }},
        'new'       : true,
        'upsert'    : true,
        'fields'    : {'_id' : true}
    };

    this.db.collection(dbName).findAndModify(args, function(err, doc){
        if(!that.getId()) {
            that.setId(doc._id);
        }

        if (typeof(callback) === "function"){
            callback.call(that);
        }
    }); 
}

I'm simply looking for the semantics of update that also happens to return a Mongo-generated _id on upsert. I do not want the values of the query clause to additionally be appended as if they were in the update map. Is there any way to achieve what I am getting at?

1

1 Answers

2
votes

You can generate the _id client side, with new new require('mongodb').ObjectID() Then you can just do a regular upsert (no need to do findandmodify) because you already have the _id.

However, if you are using findAndModify, keep in mind that the node driver accepts the arguments to this function positionally, not as an object (like in the regular mongo shell). The correct format to do findandmodify with the node driver looks like this:

collection.findAndModify(criteria, sort, update[, options, callback])

(options and callback are optional params). Full docs here: https://github.com/mongodb/node-mongodb-native/blob/master/docs/insert.md