Mongo 在 Meteor 应用程序中的 _id_ 字段上给出重复键错误

Posted

技术标签:

【中文标题】Mongo 在 Meteor 应用程序中的 _id_ 字段上给出重复键错误【英文标题】:Mongo gives duplicate key error on _id_ field in Meteor application 【发布时间】:2015-05-11 17:55:41 【问题描述】:

我正在搜索很长时间和很多关于这个问题的主题。直到现在我找不到任何解决方案。此外,这对我来说并不完全清楚,希望您能提供帮助。这是我的问题:

我设计了一个 Meteor 应用程序,Mongo DB 中有一个带有订单的集合。该集合通过读取 csv 文件填充

import_file_orders = function(file) 
var lines = file.split('%\r\n');
var l = lines.length - 1;
for (var i=0; i < l; i++) 
  var line = lines[i];
  var line_parts = line.split('|');
  var ex_key = line_parts[0];
  var ex_name = line_parts[1];
  var clin_info = line_parts[2];
  var order_info = line_parts[3];
  var clinician_last_name = line_parts[4];
  var clinician_first_name = line_parts[5];
  var clinician_code = line_parts[6];
  var clinician_riziv = line_parts[7]
  var pat_id = line_parts[8];
  Meteor.orders.insert(Patient:pat_id, Exam_code:ex_key, Exam_name:ex_name, Clinical_info:clin_info, Order_info:order_info, Clinician:first:clinician_first_name, last:clinician_last_name, c_code:clinician_code, riziv:clinician_riziv, Planned:null);
  console.log("%");
;

读取 CSV 文件后,集合中的某些文档有错误:

duplicate key error index: protocolplanner.Orders.$_id_ dup key:  :     "2ZGvRfuD8iMvRiXJd"  insert failed

当我运行 Mongo 命令 db.Orders.getIndexes() 时,我看到有两个索引:


  "v" : 1,
  "key" : 
           "_id" : 1
   ,
   "name" : "_id_",
   "ns" : "protocolplanner.Orders"
 

好像有两个索引:一个_id索引(一直存在,不能删除)和一个_id_索引。似乎是 _ id _ 索引导致了错误。所以我有三个问题:

首先:为什么会有 _ id _ 索引?我在 Meteor 代码中没有定义任何索引。 第二:为什么该索引存在 dup key 错误? 第三:似乎我无法删除 _ id _ 索引。为什么?我现在您不能删除 _id 索引,但我认为这不是 _id 索引。

如你所见,我完全迷路了。请帮忙!

编辑:

如下评论,更多信息:

我正在读取的数据量是 10151 行。在定义的客户端读取文件的函数。通过允许和拒绝规则,只有管理员用户可以将数据输入 mongo。这些行被正确读取。读取文件后,应用程序中的所有数据都可用。几秒钟后,Mongo 会自动创建索引并出现错误。从那时起,发生错误的行在应用程序中不再可见。

我在 Mongo shell 中尝试了以下操作: db.Orders.find(_id:"2ZGvRfuD8iMvRiXJd")

Mongo 给了我正确的文件。这证明 _id 确实是 Meteor 在数据插入数据库时​​创建的。但是这个 _id 应该是唯一的,所以我对我遇到的错误完全感到困惑。

编辑 2: 经过一些试验和错误,我有一些关于这个问题的新信息。也许知道这很有趣,所以我们可以找到这个问题的答案。

如上所述,当我在客户端读取数据时,即使我使用 ObjecID 而不是 Meteor ID,也会出现重复键错误。但是,当我通过 mongoinsert 命令将数据直接推送到 Mongo 时,所有数据都导入良好,并且没有出现错误。当我插入这么多数据时,似乎服务器和客户端之间存在冲突(可能是异步计时问题)。

目前我正在寻找读取数据服务器端的解决方案,希望不会发生错误。

【问题讨论】:

好吧,请不要在这个空间里问“三个问题”,因为格式是“一个问题”,以便与接受的答案相协调。但是,对于 1 和 3,MongoDB 中的 _id 字段是“主键”。它被认为是文档本身的“最终唯一标识符”。 MongoDB 本身对如何生成这个“独特”值有自己的概念。 Meteor 选择用它自己的定义来“替换”它。如果您的代码确实如图所示,那么“意图”是“主键”对于创建的每个文档都是唯一的。 好的,很抱歉这三个问题。但是,由于主键是唯一的,我不明白为什么会出现重复键错误。 如果这是客户端代码而不是在异步上下文中调用,你和我都会。考虑到主键的约束,这里的主要意图是“唯一值”。您也许可以编辑您的问题以包含有关您的操作是客户端还是服务器(猜测服务器)的更多信息。还有您正在处理的数据量。任何生成相同主键值的东西都令人担忧。但是,如果您可以添加更多信息来解释这一点,那将会很有帮助。 我正在读取的文件中的行数是 10151。当它们刚刚被读取时,应用程序中的每一行数据都是可用的。几秒钟后,控制台中出现错误(生成索引后)。之后在应用程序中看不到有错误的行。读取文件的函数在客户端定义。当我在 Mongo 控制台中使用查询中的 _id 字段进行搜索时(例如:db.Orders.find(_id:"2ZGvRfuD8iMvRiXJd")),然后我找到了正确的数据。这证明_id确实是Meteor在插入数据时创建的。通常它应该是唯一的 同意唯一的原则。将信息放在问题中比放在评论中更好。您的问题有一个编辑链接。使用它为您添加更多详细信息。 【参考方案1】:

这不会解决您的问题,但它应该为您指明正确的方向,并可能使您能够隔离可用于创建新问题的问题:

第一:为什么会有_id_ 索引?

没有。只有一个索引,它有一个名称和一个键描述符。那不是一回事。默认索引的name_id_,它的key是_id

为什么该索引存在 dup key 错误?

_id 通常是在客户端而不是服务器端创建的。问题是这些密钥从何而来,因为2ZGvRfuD8iMvRiXJd 肯定不是ObjectId。这可能是一个流星键,或者您使用了一些自定义主键,但我不知道这些键是如何生成的。也许生成密钥的任何东西都容易发生冲突?

有关这方面的更多信息会有所帮助,但我建议提出一个新问题,这样问题就不会变得太大或获得太多历史记录。

第三:我似乎也无法删除 _ id _ 索引。为什么会这样?

这是第一个答案的引理:您不能删除强制主键索引。

编辑:

流星,默认情况下,generates ids in a different way than MongoDb。这是有道理的,因为the convention for ObjectId makes collisions probable if the number of clients is large(即,如果客户端不是服务器实例,而是客户端浏览器,其中可能有 2-3 个数量级以上)。

相反,Meteor 显然使用了method to consistently generate pseudo-random numbers on client and server。令人恼火的是,该实现使用了 PRNG 和falls back to a not crypto-strong deterministic random number generator (Alea)。换句话说,找出您的 ID 是如何准确生成的可能会很棘手,因为这取决于您环境的许多细节。

解决方法: 尝试使用ObjectId 作为主键:

Orders= new Meteor.Collection('Orders', idGeneration: 'MONGO');

【讨论】:

对不起。这如何回答在稀释“为什么多个记录的主键相同”时解决的基本问题。当然内容扩展了我给自己的“评论”(在这个“答案”中提到)但是它回答了那个核心点吗?我不明白它是怎么做的。这真的只是一个很长的评论。 OP 很难隔离问题,这个答案回答了他总共提出的四个问题中的两个,并就如何隔离根本原因以创建一个更适合的新问题提供建议点。这并不总是与问答模式有关,还与帮助人们有关。我希望 OP 简化问题并发布一个新问题,而不是扩展当前问题,以更好地适应问答结构。 我想我说过,我想我说过你基本上反映了我在澄清中评论的内容,并用更长的版本来说明。这并没有“回答”“为什么会这样”的核心问题_id 值被插入”。如果您不知道答案,请发表评论。最好不要只是复制别人说过的话。 如您所见,我写的答案与您的第二条评论平行。你没有事件 attempt 来解释索引 key 和索引 name 不是一回事,所以我几乎没有复制你的评论。而是将精力集中在帮助他人上。 感谢您的回答。我在上面添加了一条评论,其中包含更多信息。但是目前我不知道出了什么问题。【参考方案2】:

目前还不清楚为什么会出现重复键错误的问题。不过我尝试了一些方法,找到了一个可行的解决方案。

我将数据的插入从客户端移动到服务器端。因此,我遵循了本主题中的解决方案:

How to import data from CSV file into Meteor collection at server side

当插入功能在服务器端时,不会出现重复键错误,并且一切正常。

【讨论】:

以上是关于Mongo 在 Meteor 应用程序中的 _id_ 字段上给出重复键错误的主要内容,如果未能解决你的问题,请参考以下文章

通过 Meteor / Mongo 返回子文档数组

Meteor:你如何用 _id 字段将一个集合中的字段填充到另一个集合中?

Meteor:你如何用 _id 字段将一个集合中的字段填充到另一个集合中?

Meteor mongo 更新嵌套数组

Mongoose - 检索到的文档中没有“_id”属性

MongoDB / Meteor / 将 MONGO_URL 导出到已部署的应用程序