1
votes

In node.js, from one javascript loop, I am trying to insert one json object into one mongodb collection but getting duplicate key error on _id column.

{ MongoError: E11000 duplicate key error collection: app.Tab2017index: id dup key: { : ObjectId('5cbc813227b2ca2864b3c66a') }

Here is my part of my javascript code, which is causing error.

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
const url = 'mongodb://localhost:27017';
const dbName = 'app';    
var jsonData = {};

  MongoClient.connect(url,{useNewUrlParser: true}, function(err, client) {
    assert.equal(null, err);
    if(err) { return console.dir(err); }
    const db = client.db(dbName);
    const collection = db.collection('Tab2017')

    for (var i = 0; i < 5; i++) {        
            jsonData["test"] = "line";                          
                console.log('LINE_'+i+'- '+JSON.stringify(jsonData));
                collection.insertOne(jsonData, (err, result) => {                       
                    if(err) { console.dir(err); }                           
                    console.log('mongodb insert done');             
                })              
        }     
  })

Above code is showing error on console,

D:\app\server\routes>node linmon.route-backup3.js
LINE_0- {"test":"line"}
LINE_1- {"test":"line","_id":"5cbc813227b2ca2864b3c66a"}
LINE_2- {"test":"line","_id":"5cbc813227b2ca2864b3c66a"}
LINE_3- {"test":"line","_id":"5cbc813227b2ca2864b3c66a"}
LINE_4- {"test":"line","_id":"5cbc813227b2ca2864b3c66a"}
mongodb insert done
-------------------------------------------
{ MongoError: E11000 duplicate key error collection: app.Tab2017 index: _id_ dup key: { : ObjectId('5cbc813227b2ca2864b3c66a') }
    at Function.create (D:\app\server\node_modules\mongodb\node_modules\mongodb-core\lib\error.js:43:12)
    at toError (D:\app\server\node_modules\mongodb\lib\utils.js:149:22)
    at coll.s.topology.insert (D:\app\server\node_modules\mongodb\lib\operations\collection_ops.js:859:39)
    at D:\app\server\node_modules\mongodb\node_modules\mongodb-core\lib\connection\pool.js:397:18
    at process._tickCallback (internal/process/next_tick.js:61:11)

I am not inserting _id columns value and allowing it to be system generated. Here is the output of getindexes.

> db.Tab2017.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "app.Tab2017"
        }
]
>

When i insert same object through mongo shell command line, it works without error. Looks like javascript does not wait for mongodb insert operation to complete.

5
Do you have any document with _id value equal to ObjectId('5cbb6bba88a60734c80302d2') in Tab2017 collection?Mani
Yes, one documents is present with ObjectId('5cbb6bba88a60734c80302d2'), which is generated from previous insertOne in Node.js loop. Surprisingly mongodb is not generated _id , which is supposed t be system generated.usersam
You need to show the actual code that reproduces the problem. The most likely cause is you have an instance and you're altering some data in that instance to save a new item but not realizing the _id value ( which is likely assigned in another operation ) does not change in the operation you are actually doing. But in order to correct your code, you actually need to show the offending code which is producing the problem.Neil Lunn
@Neil Lunn, i have added part of code.usersam
Ahh. This is a scoping problem. insertOne() actually mutates the jsonData object to include the _id value. And of course it stays the same, since every iteration after the first already includes the _id field and attempts to "insert" it. Basically you should move the declaration of jsonData = {} or whatever other valid initialization needs to be done to inside the for loop. You should also discover insertMany(), which can take an array of documents. The latter basically means you don't need to "loop" the actual inserts to MongoDB.Neil Lunn

5 Answers

1
votes

I have solved the problem myself. Nodejs performs asynchronous operation so it completes the loop but keeps inserting into mongodb collection as well. I noticed that, first operation always gets successful and fails for subsequent inserts. Somehow mongodb generates "_id" value for first insert and keeps that same "_id" in json objects. That's why it throws duplicate error. I just added one line to remove "_id" from json object before mongo insert and it worked.

Here is my modified code.

for (var i = 0; i < 5; i++) {        
            jsonData["test"] = "line"; 
            **delete jsonData["_id"];**
                console.log('LINE_'+i+'- '+JSON.stringify(jsonData));
                collection.insertOne(jsonData, (err, result) => {                       
                    if(err) { console.dir(err); }                           
                    console.log('mongodb insert done');             
                })              
        } 
0
votes

Just delete the _id field from the object before going to insert.

delete jsonData["_id"];

If you use mongoose just try with this.

jsonData["_id"] = new mongoose.Types.ObjectId();

Definitely this will solve your problem and you can maintain uniqueness by without droping indexes.

0
votes

I had a similar issue. The problem was scope (as mentioned above in a comment by Neil Lunn).

I was inserting a document into a collection through a Netlify serverless function (Lambda function). I had no DB-Schema. First entry worked fine. All subsequent entries failed.

The code that was failing:

const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient
const myInitialDocument = { title: null }

function createClient (connectionString) {
  const client = new MongoClient(
    connectionString,
    { useNewUrlParser: true, useUnifiedTopology: true }
  )
  return client
}

exports.handler = async function (event) {
  const dbClient = createClient('connection_string_to_db')
  let entryToDb

  try {
    await dbClient.connect()
    entryToDb = await dbClient.db().collection('somecollection').insertOne(myInitialDocument)
  } catch (err) {
    console.log(err)
  }
  dbClient.close()
  return {
    body: JSON.stringify(entryToDb)
  }
}

The problem above is that myInitialDocument gets mutated and after the initial call it includes the _id.

Updated code that worked (has no myInitialDocument const):

const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient

function createClient (connectionString) {
  const client = new MongoClient(
    connectionString,
    { useNewUrlParser: true, useUnifiedTopology: true }
  )
  return client
}

exports.handler = async function (event) {
  const dbClient = createClient('connection_string_to_db')
  let entryToDb

  try {
    await dbClient.connect()
    entryToDb = await dbClient.db().collection('somecollection').insertOne({ title: null })
  } catch (err) {
    console.log(err)
  }
  dbClient.close()
  return {
    body: JSON.stringify(entryToDb)
  }
}
-1
votes

_id field in MongoDB is a unique key field. You cannot insert duplicate values to the _id column.

For example, you have a document with _id value equal to 1 exist in the collection and you are trying to insert one more document with same _id value(1) you will get the E11000 duplicate key error.

In your case, you are not generating a new _id value when inserting the second document which results in a duplicate error. Try creating a new _id for every insert or don't pass the _id value so that MongoDB backend will take care of this.

-3
votes

You might need to drop the index,then try to insert .

db.collection.dropIndex()