Search code examples
node.jsmongodbuuidmonk

Why can't I use a string uuid for a custom MongoDB _id in my NodeJS app?


I am developing a NodeJS app with a MongoDB database (using the native MongoDB NodeJS driver) and would like to use a string as my primary key.

This insertion fails for me when _id is a string:

   collection.insert({_id : "customId", name : "sampleName", email : "sampleEmail"}, {}, function(err, result) {
        if (err) {
            res.send({msg : err});
        }
        else {
            res.send({msg : 'SUCCESS'});
        }
    });

This code is in my NodeJS app. When I try the same insertion through the mongo shell commands on my database, it works fine.

I know that custom _id fields for MongoDB primary keys must be guaranteed to be unique. I plan to use a uuid string in my code, but no string _id seems to work. I read here https://docs.mongodb.org/manual/core/document/#field-names that _id must be unique and can be of any type except array. I have also reviewed this question Creating custom Object ID in MongoDB which is similar, but it hasn't solved my issue. Why can't I use a string as a custom _id field?

Edit: The error message says "[Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters]"

Edit 2:

Here is my full code:

router.post('/addcontact', function(req, res) {
var db = req.db;
var newContact = req.body;
var newContactId = uuid.v4();
var newContactId = String(newContactId);
//newContact['_id'] = newContactId;
var collection = db.get('contactlist');
console.log("about to do insert");
try {
    collection.insert({_id : '4BF6EFC6-1682-4A40-A0DE-8CD104AC92D3', name : "testName", email : "testEmail", phone : "testPhone"}, {}, function(err, result){
        if (err) {
            res.send({msg : err});
        }
        else {
            res.send({msg : 'SUCCESS'});

            // log operation in log file with Kafka
            var producer = req.kafkaProducer;
            var payload = {topic : 'logging', messages: 'POST /addcontact id:' + newContactId + ' ' + newContact["name"]};
            producer.send([payload], function (err, data) {
            // console.log(data);
            });
        }
    });
}
catch (err) {
    console.log(err);
} });

Note that I am not actually using the newContact info from the http POST, but just trying to get a sample insert to work.

Here is the console print out with the error:

about to do insert
[Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters]
POST /contacts/addcontact - - ms - -

Here is my package.json with dependencies:

{
  "name": "NodeApp2",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "async": "..",
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "couchbase": "^2.1.2",
    "debug": "~2.2.0",
    "express": "~4.13.1",
    "jade": "~1.11.0",
    "kafka-node": "..",
    "kerberos" : "..*",
    "mongodb": "2.0.49",
    "monk": "~1.0.1",
    "morgan": "~1.6.1",
    "node-gyp": "^3.1.0",
    "serve-favicon": "~2.3.0"
  }


Solution

  • So you're not actually using mongodb directly, but through monk (db.get('contactlist') gave it away...), and monk automatically casts _id to ObjectId, which is why you're getting that error.

    It looks like this behaviour can't be turned off, so you probably have to migrate your code to mongodb.