就像在MYSQL中一样,我想要一个自增的ID。
您需要使用MongoDB的findAndModify命令。通过它,您可以原子地选择并增加一个字段。
db.seq.findAndModify({
query: {"_id": "users"},
update: {$inc: {"seq":1}},
new: true
});
这将为users
集合的计数器加一,然后您可以在插入文档之前将其添加到文档中。由于它是原子操作,您不必担心竞争条件导致冲突的ID。
这并不像MySQL的auto_increment
标志那样无缝,但通常您还可以在Mongo驱动程序中指定自己的ID工厂,因此您可以实现一个使用findAndModify来透明地增加和返回ID的工厂,从而获得更类似于MySQL的体验。
这种方法的缺点是,由于每次插入都依赖于对序列集合的写锁定,如果您进行大量写操作,可能很快就会出现瓶颈。如果您只想保证集合中的文档按插入顺序排序,请查看Capped Collections。
MongoDB旨在实现水平扩展。在这种情况下,自动递增会导致id碰撞。这就是为什么id更像是guid/uuid的原因。
MongoDB提供了两种自动递增_id (或自定义键) 的方式:
在这种方法中,我们需要创建一个集合来存储最大键的数量,并且每次调用该函数时将其递增1。
1. 存储函数
function getNextSequence(collectionName) {
var ret = db.counters.findAndModify({
query: { _id: collectionName },
update: { $inc: { seq: 1 } },
new: true,
upsert: true
});
return ret.seq;
}
2. 插入文档
db.users.insert({
_id: getNextSequence("USER"),
name: "Nishchit."
})
在这种模式中,乐观循环会计算增加的_id值,并尝试插入一个具有计算出的_id值的文档。如果插入成功,则循环结束。否则,循环将遍历可能的_id值,直到插入成功。
1. 存储函数
function insertDocument(doc, targetCollection) {
while (1) {
var cursor = targetCollection.find( {}, { _id: 1 } ).sort( { _id: -1 } ).limit(1);
var seq = cursor.hasNext() ? cursor.next()._id + 1 : 1;
doc._id = seq;
var results = targetCollection.insert(doc);
if( results.hasWriteError() ) {
if( results.writeError.code == 11000 /* dup key */ )
continue;
else
print( "unexpected error inserting data: " + tojson( results ) );
}
break;
}
}
2. 插入文档
var myCollection = db.USERS;
insertDocument(
{
name: "Nishchit Dhanani"
},
myCollection
);
来自 MongoDB 官方文档 的指南。
如果你怀疑你的数据可能跨越多个服务器(也称为分片),那么请遵循Dennis的建议并使用本地的ObjectId。
如果你更喜欢int/long id(在URL上看起来更好),那么你可以从Chris建议的一个简单的生成器实现开始。当/如果性能/锁定成为问题时,你可以升级你的生成器以实现Hi/Lo算法。这将大大减轻对'seq'集合的压力,并实际上消除这个问题。(客户端生成器使用一个'pool',只有在没有更多的空闲id时才联系数据库)
@Dennis Burton 如果用户自动递增,不会导致冲突吗?我认为,因此MongoDB使用自己的_Id来避免冲突,但是如果用户希望将某列作为运行序列,则可以自由设置
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
autoIncrement = require('mongoose-auto-increment');
var connection = mongoose.createConnection("mongodb://localhost/myDatabase");
autoIncrement.initialize(connection);
var bookSchema = new Schema({
author: { type: Schema.Types.ObjectId, ref: 'Author' },
title: String,
genre: String,
publishDate: Date
});
bookSchema.plugin(autoIncrement.plugin, 'Book');
var Book = connection.model('Book', bookSchema);