首页 > 解决方案 > mongoDB / Node.js 上的重复索引

问题描述

我这边奇怪的问题/行为:我有一个 _id 字段上具有唯一索引的 mongoDB 集合。

为了向集合中添加一个元素并确保我不会删除已经存在的文档,我使用了这个请求:

db.getCollection('name').updateOne({
  "_id": "5bf9c75b478b493e9c989d96"
}, {
  "$setOnInsert": {
    "_id": "5bf9c75b478b493e9c989d96",
    "offset": 53,
    "data": {
      // some data
    }
  }
}, {
  'upsert' : true
})

如果我没记错的话,这意味着:尝试找到 :id,如果它不存在,则插入漂亮的结构。如果找到 :id,则不会触发 $setOnInsert 并且忽略请求。

这在 robomongo 中完美运行,但是当我尝试将它集成到我的 node.js 程序时,如果找到具有现有 :id 的结构,它会引发重复的 Id 异常,因为它似乎仍在尝试编写它。

我们是否同意整个操作(查找、设置、修改或不是集合)应该是原子的?我知道问题出在我在微服务环境中这样做的事实,这么多线程试图在 Mongo 上执行相同的操作,这就是为什么我需要它是原子的。

编辑按照亚历克斯的回答:

蒙戈错误:

{
  "driver": true,
  "name": "MongoError",
  "index": 0,
  "code": 11000,
  "errmsg": "E11000 duplicate key error collection: eventSourcing.name index: _id_ dup key: { : ObjectId('5bfbd5a0478b493e9c989db0') }"
}

我的代码:

public saveIfAbsent(aggregate: T, writer: Writer<T, Schema>): Promise<UpdateWriteOpResult> {
  const element = writer(aggregate)

  if (element['_id'] !== aggregate._id) {
    throw new Error("should not happen")
  }

  return super.collection().then((collection) => {
    return collection.updateOne({
      '_id': aggregate._id
    }, {
      '$setOnInsert': element
    }, {
      'upsert' : true
    })
  }).catch((e) => {
    console.log(e)
    return Promise.reject(e)
  })
}

关于如何使它发挥作用的任何想法?我想要的东西只有在结构不在这里时才能写,否则不做任何事情。

谢谢

编辑:

看来我正在尝试做一些不可能的事情……或者我做错了。

const db = new Database()

const data = new Array<string>()
const length = 500; // user defined length

for (var i = 0; i < length; i++) {
  data.push('toto')
}

Promise.all(data.map((e) => db.db.then((db) => db.collection('name').updateOne({
  '_id': 1,
}, {
  '$setOnInsert': {
    'id': 1,
    'data': e
  }
}, {
  upsert: true
})))).then(() =>
  console.log('true'))

这段代码试图推入 base { 'id': 'data': 'toto' }。

预期行为:

当前行为:

用于节点 JS v3.1.10 的本机 mongo DB 驱动程序

我试图在我的代码中有预期的行为,有什么办法吗?

标签: node.jsmongodb

解决方案


this.representationId(aggregate)不返回相同的数据/类型element._id

之前检查它:

if (this.representationId(aggregate) !== element._id) {
    throw new Error("Impossible happened!")
}

element._id在查询中使用

return collection.updateOne({
    '_id': element._id
  }, {
    '$setOnInsert': element
  }, {
    'upsert': true
  })
})

或者两者都做。


推荐阅读