【问题标题】:node.js db.collection.insertOne - MongoError: E11000 duplicate key error collection: _id_ dupnode.js db.collection.insertOne - MongoError:E11000 重复键错误集合:_id_ dup
【发布时间】:2019-09-10 14:56:39
【问题描述】:

在 node.js 中,我试图从一个 javascript 循环中将一个 json 对象插入到一个 mongodb 集合中,但在 _id 列上出现重复键错误。

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

这是我的 javascript 代码的一部分,它导致了错误。

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');             
                })              
        }     
  })

以上代码在控制台显示错误,

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)

我没有插入 _id 列值并允许它由系统生成。这是 getindexes 的输出。

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

当我通过 mongo shell 命令行插入相同的对象时,它可以正常工作。看起来 javascript 不等待 mongodb 插入操作完成。

【问题讨论】:

  • Tab2017 集合中有没有_id 值等于 ObjectId('5cbb6bba88a60734c80302d2') 的文档?
  • 是的,存在一个带有 ObjectId('5cbb6bba88a60734c80302d2') 的文档,它是从 Node.js 循环中的先前 insertOne 生成的。令人惊讶的是 mongodb 没有生成 _id ,它应该是系统生成的。
  • 您需要显示重现问题的实际代码。最可能的原因是您有一个实例,并且您正在更改该实例中的一些数据以保存新项目,但没有意识到 _id 值(可能在另一个操作中分配)在您实际执行的操作中没有改变正在做。但为了更正您的代码,您实际上需要显示导致问题的违规代码
  • @Neil Lunn,我添加了部分代码。
  • 啊。这是一个范围界定问题。 insertOne() 实际上改变了 jsonData 对象以包含 _id 值。当然它保持不变,因为第一次迭代之后的每次迭代都已经包含_id 字段并尝试“插入”它。基本上,您应该将 jsonData = {} 的声明或任何其他需要进行的有效初始化移动到 inside for 循环。您还应该发现insertMany(),它可以获取一组文档。后者基本上意味着您不需要将实际插入“循环”到 MongoDB。

标签: node.js mongodb


【解决方案1】:

我自己解决了这个问题。 Nodejs 执行异步操作,因此它完成了循环,但也不断插入到 mongodb 集合中。我注意到,第一次操作总是成功并且后续插入失败。 mongodb 以某种方式为第一次插入生成“_id”值,并在 json 对象中保持相同的“_id”。这就是它抛出重复错误的原因。我只是在 mongo 插入之前添加了一行以从 json 对象中删除“_id”并且它起作用了。

这是我修改后的代码。

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');             
                })              
        } 

【讨论】:

  • for 循环的实例内部中声明jsonData 之类的东西实际上更好。如果您想重用在范围外声明的对象,请执行insertOne({ ...jsonData }) 之类的操作,这基本上是对象数据的克隆,但不是同一个对象引用。原因是 无论好坏 前一段时间做出的决定是正确 要做的事情确实是改变传入的对象引用到基于insert 的方法中,并添加_id 在不存在时分配的值。使用新实例/克隆可避免删除 _id
  • @usersam... 你是如何得到 _id 来删除它的?你能显示删除 _id 的代码吗?
【解决方案2】:

在插入之前从对象中删除 _id 字段。

delete jsonData["_id"];

如果你使用猫鼬,试试这个。

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

这肯定会解决您的问题,并且您可以通过不删除索引来保持唯一性。

【讨论】:

    【解决方案3】:

    我遇到了类似的问题。问题在于范围(正如上面 Neil Lunn 的评论中所述)。

    我通过 Netlify 无服务器函数(Lambda 函数)将文档插入到集合中。我没有 DB-Schema。第一个条目工作得很好。所有后续条目均失败。

    失败的代码:

    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)
      }
    }
    

    上面的问题是myInitialDocument 发生了变异,在初始调用之后它包含了_id

    更新的有效代码(没有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)
      }
    }
    

    【讨论】:

      【解决方案4】:

      _id MongoDB 中的字段是唯一的关键字段。您不能在_id 列中插入重复值。

      例如,您有一个 _id 值等于 1 的文档存在于集合中,并且您尝试再插入一个具有相同 _id 值的文档(1),您将收到 E11000 重复键错误

      在您的情况下,您在插入第二个文档时没有生成新的 _id 值,这会导致重复错误。尝试为每个插入创建一个新的 _id 或不传递 _id 值,以便 MongoDB 后端处理此问题。

      【讨论】:

      • 我同意解释,但我没有传递 _id 值。
      【解决方案5】:

      您可能需要删除索引,然后尝试插入。

      db.collection.dropIndex()
      

      【讨论】:

      • _id 是每个集合的默认索引,不能删除。
      猜你喜欢
      • 2021-07-25
      • 2021-10-01
      • 1970-01-01
      • 2021-09-02
      • 2018-07-29
      • 2019-01-05
      • 2020-05-11
      • 2023-03-25
      • 2018-07-26
      相关资源
      最近更新 更多