我正在制作一个分析系统,API调用将提供唯一用户ID,但它不是连续的且太稀疏。
我需要给每个唯一的用户ID分配自动增量ID,以在位数组/位集中标记分析数据点。因此,第一个遇到的用户对应于位数组中的第一个位,第二个用户对应于位数组中的第二个位,依此类推。
那么,在MongoDB中生成递增的唯一用户ID是否有可靠且快速的方法?
我正在制作一个分析系统,API调用将提供唯一用户ID,但它不是连续的且太稀疏。
我需要给每个唯一的用户ID分配自动增量ID,以在位数组/位集中标记分析数据点。因此,第一个遇到的用户对应于位数组中的第一个位,第二个用户对应于位数组中的第二个位,依此类推。
那么,在MongoDB中生成递增的唯一用户ID是否有可靠且快速的方法?
如选定答案所述,您可以使用findAndModify生成序列号。
但我强烈反对认为您不应该这样做的观点。这完全取决于您的业务需求。拥有12字节的ID可能会消耗大量资源,并在未来引起重大的可扩展性问题。
我在这里详细回答了这个问题。
.createIndex ( { "number" : 1 }, { unique : true } )
,其中数字1代表递增,-1代表递减。 - Tino Costa 'El Nino'number
字段上创建了一个索引,并且该索引是增量的并强制唯一性,它并不会自动增加字段,甚至不需要默认值。 - Amr Saber_id
从12字节更改为4字节(BJSON限制)对于那些从12字节开始出现扩展问题的集合来说,可能会在一段时间后溢出。此外,您节省的这些字节相当于用户输入的8个字符(如果集合包含用户输入,这几乎总是情况),根本不值得付出努力和失去所有好处。 - Amr SaberfindAndModify
并发将不会成为问题。另请参阅http://www.mongodb.org/display/DOCS/Object+IDs和HiLo算法:https://dev59.com/ZXVC5IYBdhLWcg3weBA- - mnemosyn我知道这是一个老问题,但我将发布我的答案供后人参考...
这取决于您正在构建的系统和特定的业务规则。
我正在使用MongoDb、C# (后端 API)和Angular (前端 Web 应用程序)构建中到大型的 CRM,发现 ObjectId 在 Angular 路由中选择特定实体方面非常糟糕。同样适用于API控制器路由。
上面的建议对我的项目非常有效。
db.contacts.insert({
"id":db.contacts.find().Count()+1,
"name":"John Doe",
"emails":[
"john@doe.com",
"john.doe@business.com"
],
"phone":"555111322",
"status":"Active"
});
对于我的情况,它是完美的解决方案,但并非适用于所有情况。正如上面的评论所述,如果你从集合中删除了3条记录,则会出现碰撞。
我的业务规则规定,由于我们内部SLA(服务级别协议)的原因,不允许在我正在编写的应用程序潜在生命周期之外删除通信数据或客户记录,因此,我只需用一个枚举“状态”标记记录,其值为“Active”或“Deleted”。你可以从UI中删除某些内容,它会显示“联系人已被删除”,但应用程序实际上只是更改了该联系人的状态为“Deleted”,当应用程序调用存储库以获取联系人列表时,我会在将数据推送到客户端应用程序之前过滤掉已删除的记录。
因此,db.collection.find().count() + 1 对于我来说是完美的解决方案......
它并不适用于所有人,但如果您不会删除数据,那么它就可以正常工作。
编辑
pymongo的最新版本:
db.contacts.count() + 1
lastContact = db.contacts.find().sort({$natural:-1}).limit(1)[0];
db.contacts.insert({
"id":lastContact ?lastContact ["id"] + 1 : 1,
"name":"John Doe",
"emails": ["john@doe.com", "john.doe@business.com"],
"phone":"555111322",
"status":"Active"
})
id
。
更多解释:我只是获取最新插入文档的 id
,将其加一,然后将其设置为新记录的 id
。三元运算符用于当我们还没有任何记录或所有记录都被删除的情况。// await collection.insertOne({ autoIncrementId: 1 });
const { value: { autoIncrementId } } = await collection.findOneAndUpdate(
{ autoIncrementId: { $exists: true } },
{
$inc: { autoIncrementId: 1 },
},
);
return collection.insertOne({ id: autoIncrementId, ...data });
第一条记录应该被添加
"_id" = 1 in your db
$database = "demo";
$collections ="democollaction";
echo getnextid($database,$collections);
function getnextid($database,$collections){
$m = new MongoClient();
$db = $m->selectDB($database);
$cursor = $collection->find()->sort(array("_id" => -1))->limit(1);
$array = iterator_to_array($cursor);
foreach($array as $value){
return $value["_id"] + 1;
}
}
_id
已经被索引了,但是仍然会占用很多内存。 - Amr Saber我遇到了类似的问题,即我想生成唯一的数字作为标识符,但不一定必须如此。我想出了以下解决方案。首先初始化集合:
fun create(mongo: MongoTemplate) {
mongo.db.getCollection("sequence")
.insertOne(Document(mapOf("_id" to "globalCounter", "sequenceValue" to 0L)))
}
然后提供一个返回唯一(且递增)数字的服务:
@Service
class IdCounter(val mongoTemplate: MongoTemplate) {
companion object {
const val collection = "sequence"
}
private val idField = "_id"
private val idValue = "globalCounter"
private val sequence = "sequenceValue"
fun nextValue(): Long {
val filter = Document(mapOf(idField to idValue))
val update = Document("\$inc", Document(mapOf(sequence to 1)))
val updated: Document = mongoTemplate.db.getCollection(collection).findOneAndUpdate(filter, update)!!
return updated[sequence] as Long
}
}
我相信id不会像其他解决方案一样在并发环境中出现弱点。
// First check the table length
const data = await table.find()
if(data.length === 0){
const id = 1
// then post your query along with your id
}
else{
// find last item and then its id
const length = data.length
const lastItem = data[length-1]
const lastItemId = lastItem.id // or { id } = lastItem
const id = lastItemId + 1
// now apply new id to your new item
// even if you delete any item from middle also this work
}
这可能是另一种方法
const mongoose = require("mongoose");
const contractSchema = mongoose.Schema(
{
account: {
type: mongoose.Schema.Types.ObjectId,
required: true,
},
idContract: {
type: Number,
default: 0,
},
},
{ timestamps: true }
);
contractSchema.pre("save", function (next) {
var docs = this;
mongoose
.model("contract", contractSchema)
.countDocuments({ account: docs.account }, function (error, counter) {
if (error) return next(error);
docs.idContract = counter + 1;
next();
});
});
module.exports = mongoose.model("contract", contractSchema);