8

I'm doing a rest api to exchange data between a mongo database and a web app. These data are json formatted.

I have a trouble when it comes to update a document:

cannot change _id of a document.

As a matter of fact, in my JSON the _id of the doc is stored as a string and deserialized as a string. Whereas it is stored as an ObjectID in mongo. This explains why mongo raises an error.

  • In mongo: _id: ObjectId('51051fd25b442a5849000001')
  • In JSON: _id:"51051fd25b442a5849000001"

To avoid this I manually convert the _id property from a string to an ObjectID. But It seems ugly and will fail with other BSON types.

Q: Is there a clean way to avoid that or to do a nice JSON/BSON conversion?

Below is the code I use to update a document. I'm using nodejs with express and mongodb with the native driver.

exports.updateById = function(req, res) {
var id = req.params.id;
var map = req.body;

map._id = new ObjectID.createFromHexString( map._id); // Manual conversion. How to avoid this???

console.log( 'Updating map: ' + id);
console.log( 'Map: ' + JSON.stringify( map));

db.collection('maps', function(err, collection) {
    if(err) throw err;
    collection.update(
        {'_id': new BSON.ObjectID(id)}, map, {safe:true}, 
        function(err, result) {
            if (err) {
                console.log('Updating map err: ' + JSON.stringify( err));
                res.json( 500, {'message':'An error has occurred while updating the map', 'error': err});
            } else {
                console.log('Updating succeed');
                res.send(map);
            }
        }
    );
});

};

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
t4ncr3d3
  • 615
  • 1
  • 8
  • 17

1 Answers1

11

Because you can't modify the _id field, a better approach is to simply remove the that field from your map object instead of converting it to an ObjectId.

So this:

delete map._id;

instead of this:

map._id = new ObjectID.createFromHexString( map._id);

If you want to return the updated object like you're attempting with res.send(map);, you should be using findAndModify instead of update so you have access to the resulting doc and not just what was posted.

JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
  • 1
    Thanks. It's fine with the doc _id. But I don't understand why it is not able to deserialize the _id into an ObjectID? WHat will happen if I add other bson types in my document? – t4ncr3d3 Jan 29 '13 at 15:02
  • 1
    @t4ncr3d3 The native mongo driver contains very minimal type casting. If you're looking for better support in this area, I'd suggest using [Mongoose](http://mongoosejs.com/) which takes care of this type of casting for you. – JohnnyHK Jan 29 '13 at 15:30
  • @t4ncr3d3 Because the `_id` is not required to be an `ObjectID`, so it can't just assume that's what you want. – Aaron Dufour Jan 29 '13 at 17:03
  • @JohnnyHK Mongoose requires schema setup and a lot of other work not related to saving/retrieving documents - the native Mongo driver should be able to re-save a JSON document with a String _id. – mikemaccana Oct 30 '13 at 15:16
  • Mongoose also is broken on bulk inserts as of now. – Stephan Kristyn Feb 25 '15 at 10:41
  • delete map._id; doesnt work on mongoose objects. How can I delete _id field from them? – MeetJoeBlack Aug 02 '15 at 18:10
  • @MeetJoeBlack See [this question](http://stackoverflow.com/questions/7503450/how-do-you-turn-a-mongoose-document-into-a-plain-object) about how to freely modify mongoose objects. – JohnnyHK Aug 03 '15 at 03:17
  • If I remove the Mongo Object from the _id , how could I use this in my other backend implementations, since _id mongoObject was in nodejs – Arul Jun 28 '23 at 06:21