我想为新插入文档的“ _id”字段赋值。 ID字段必须从0开始,并且不能跳过数字。仅当没有包含重复内容的文档时才能插入。
目前这就是我所拥有的。
db.system.js.save({
_id: "nextId",
value: function (x) {
return db.counters.findAndModify({
query:{_id:x},
update:{$inc:{value:1}},
new:true
}).value;
}
})
db.loadServerScripts() // make the nextId available directly or via $where clause
db.counters.insert({_id: "_id", value: 0})
db.test.update(
{"value": "abc"},
{$setOnInsert: {"_id": nextId("_id"), "value": "abc"}},
{upsert: true}
)
如果没有包含重复的“值”字段的文档,则一切正常。当有重复的“值”字段时,即使在$ setOnInsert标记内,nextId(“ _ id”)JavaScript函数仍会被调用。因此,这里观察到的不正确行为将是一些“ _id”数字将被使用/浪费,但不能分配给有效的新文档。正确/预期的行为是仅在实际插入新文档时才调用nextId()的情况。
问题:在MongoDB中是否有解决方法来实现正确/预期的行为?
MongoDB版本:v3.4.10(本地安装)和v3.4.15(mlab MongoDB托管)
注意:我已经放弃了这个问题,并决定放宽对“不能跳过数字”的要求。修改后的要求是在全局范围内使用尽可能少的ID,同时确保所使用的ID具有尽可能低的值。在放宽需求变更之后,我设计了一个更好且可扩展的解决方案。
1)为每个客户端预留少量ID。结果将是:
db.counters.findAndModify({
query: {_id:"_id"},
update: {$inc: {"_id_beg": 10, "_id_end": 10}},
new: true
})
2)对于每个客户的插入,请使用以下
db.test.findAndModify({
query: {"value": <input value>},
update: {$setOnInsert: {"_id": <use lowest reserved id>, "value": <input value>"}
upsert: true,
new: true
})
3)对于每个客户端的插入响应,findAndModify返回的值包含nextId。如果nextId与最低保留ID相同,则表示已使用它。如果不同,则意味着另一个客户端插入了相同的值,我们可以使用保留的ID以便以后插入
在某些情况下会进行特定的优化,例如_id上的唯一索引,崩溃的客户端中未使用的值等,以允许崩溃恢复
答案 0 :(得分:0)
环顾四周,我发现:https://stackoverflow.com/a/43695770/10026557
我对其进行了测试,看起来它可以工作:
db.test.update(
{"value": "bca"},
{$setOnInsert: {"_id": db.test.find().count() + 1, "value": "bca"}},
{upsert: true}
)
额外的奖励不必依靠其他集合和/或javascript逻辑。