node.js - 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' }。
预期行为:
第一个循环,它什么也没找到,然后插入一个 { 'id': 'data': 'toto' } 因为标志 '$setOnInsert' 处于活动状态
所有其他, { '_id': 1 } 应该返回一些东西,所以 '$setOnInsert' 不应该被写,所以它应该“通过”什么都不做
当前行为:
第一个循环,它什么也没找到,然后插入一个 { 'id': 'data': 'toto' } 因为标志 '$setOnInsert' 处于活动状态
与
UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key error collection: eventSourcing.name index: _id_ dup key: { : 1 }
. 不知何故,它似乎试图在 '$setOnInsert' 部分中写一些东西 => 这似乎只有在从数据库中删除集合名称时才会发生。如果集合已经存在,它似乎不会崩溃(令人惊讶)
用于节点 JS v3.1.10 的本机 mongo DB 驱动程序
我试图在我的代码中有预期的行为,有什么办法吗?
解决方案
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
})
})
或者两者都做。
推荐阅读
- powershell - 缺少 PowerShell 类方法描述
- php - 如何在刀片中调用此值
- python - 从 GStreamer 实时接收 Numpy 数组
- asp.net-core - ASP.NET Core UserManager 中的取消
- python - Python:requests.exceptions.ConnectionError: HTTPConnectionPool(),Max retries exceeded with url
- r - lrm 警告“当前权重被忽略”
- json - 如何用jq过滤和替换json中的值
- hive - Presto/Athena 中嵌套日期分区的比较查询
- android - Android Q (10) - 当应用程序在应用程序堆栈中作为后台时,应用程序图标不显示
- wordpress - 如何删除此跳转到内容 wordpress 错误?