MongoDB重复键错误

所以现在我正在开发一个服务来允许多个事件在MongoDB上存储数据。 他们通过在每次发生新事件时在MongoDB上创build新的集合来存储事件数据。 如果同一事件需要存储一组不同的数据,则应该创build一个MongoDB中的新文档。

下面的代码是我创build的服务来处理这个。

import WhiteBoardEvent from '../model/event.model'; import IEventStore from '../interface/eventStore.interface'; import * as MongoClient from 'mongodb'; export class EventStore implements IEventStore { private mongoDBEndpoint = "mongodb://192.168.10.10:27017"; public insert(event: WhiteBoardEvent, callback: (err: any) => void): void { MongoClient.connect(this.mongoDBEndpoint, { connectTimeoutMS: 1000 }, (connErr, db) => { if (connErr) { db.close(); callback(connErr); return; } this.getNextSequence(db, event, (err, sequence) => { if (err) { db.close(); callback(err); return; } event.sequence = sequence; db.collection(event.roomId).insert(event, (err) => { db.close(); callback(err); }); }); }); } private createCounterCollection(db: MongoClient.Db, event: WhiteBoardEvent, callback: (err: any) => void): void { db.collection("counters").insert({ roomId: event.roomId, sequence: 0 }, callback); } private getNextSequence(db: MongoClient.Db, event: WhiteBoardEvent, callback: (err: any, sequence: number) => void): void { var collection = db.collection("counters"); collection.findOneAndUpdate( { roomID: event.roomId }, { $inc: { sequence: 1 }, // new: true }, { upsert: true, returnOriginal: false }, (err, r) => { if (err) { this.createCounterCollection(db, event, (err) => { if (err) { callback(err, -1); return; } callback(null, 0); }); return; } callback(null, r.value.sequence); console.log("counter : " + r.value.sequence); } ); } } 

下面的代码是我创build的testing文件,以便我可以看到MongoDB中的更改。

 import * as timers from 'timers'; import WhiteBoardEvent from './data/model/event.model'; import { EventStore } from './data/service/eventStore.service'; var model = new WhiteBoardEvent(); model.name = "t2"; model.roomId = "testRoom"; model.timestamp = new Date(); model.userId = ""; var model2 = new WhiteBoardEvent(); model2.name = "t1"; model2.roomId = "testRoom2"; model2.timestamp = new Date(); model2.userId = ""; var eventStore = new EventStore(); var timer1 = timers.setInterval(()=>{ eventStore.insert(model, (err)=>{ if(err){ console.log(err); }else{ console.log("Test Completed!"); } }); }, 1000); var timer2 = timers.setInterval(()=>{ eventStore.insert(model2, (err)=>{ if(err){ console.log(err); }else{ console.log("Test Completed!"); } }); }, 1000); 

这是我得到的输出的一个片段。 在这里,“testing完成”显示为第一个实例,之后,我得到重复的错误。

 counter : 1 counter : 1 Test Completed! Test Completed! counter : 2 { MongoError: E11000 duplicate key error collection: admin.testRoom index: _id_ dup key: { : ObjectId('59d5da14cedd6f28a5db8c93') } 

谁能帮我这个? 先谢谢你!

您正在创build两个WhiteBoardEvent实例,没有显式设置一个ID(这很好,但相关)。 看一下你上面代码的摘录:

 db.collection(event.roomId).insert(event, (err) => { db.close(); callback(err); }); 

event交给MongoDB的insert ,会检查它是否有一个ID–它不会。 因此,MongoDB代码会为您生成一个ID(请参见此处 )。 这非常棒 – 这就是你想要的。

但是, 一次调用setIntervalcallback会发生什么? 那么, modelmodel现在有一个ID集 – 它是根据我刚刚描述的规则设置的。 在这种情况下,现在model上的一个ID被设置为insert ,您试图重复使用与MongoDB代码一样的ID。

在您的testing代码中,您可以简单地清除eventStore.insertcallback中的ID,以确保每次都生成一个新的ID。 例如:

 eventStore.insert(model, (err)=>{ model._id = null; if(err){ console.log(err); }else{ console.log("Test Completed!"); } }); 

在你的计划中,你可能有一个关键的unique: true 。 使用相同的键或未填写的键添加另一个对象将导致重复的键错误。 因为,如果一个字段没有填写,它将被填充为null。 所以2次null是一个重复键错误。 确保这不会发生。

使用sparse: true而不是unique: true 。 另外请注意,具有unique: true的字段永远不能拥有两个相同的密钥。 稀疏只能在内部有多个空值(未定义),并且与unique: true

在你的情况下,你必须在“”上乘以userid,这可能会导致错误,如果它设置为唯一的。 model.userId = "";

希望这将解决你的答案。 否则请告诉我们你的模型。

斯文