46

我正在制作一个分析系统,API 调用会提供一个唯一的用户 ID,但它不是按顺序排列的而且太稀疏了。

我需要为每个唯一用户 ID 提供一个自动增量 ID,以在 bitarray/bitset 中标记分析数据点。因此,第一个用户遇到的将对应于 bitarray 的第一位,第二个用户将是 bitarray 中的第二位,依此类推。

那么有没有一种可靠而快速的方法来在 MongoDB 中生成增量唯一用户 ID?

4

8 回答 8

32

正如所选答案所说,您可以使用 findAndModify 生成顺序 ID。

但我强烈不同意你不应该这样做的观点。这一切都取决于您的业务需求。拥有 12 字节的 ID 可能会非常消耗资源,并且在未来会导致严重的可伸缩性问题。

在这里有详细的答案。

于 2013-01-21T06:11:15.520 回答
28

你可以,但你不应该 https://web.archive.org/web/20151009224806/http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/

mongo 中的每个对象都已经有一个 id,它们可以按插入顺序排序。获取用户对象的集合、对其进行迭代并将其用作递增的 ID 有什么问题?呃完全去做那种map-reduce的工作

于 2011-12-05T10:47:55.563 回答
14

我知道这是一个老问题,但我会为后代发布我的答案......

这取决于您正在构建的系统和特定的业务规则。

我正在使用 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,我们不允许删除通信数据或客户记录的时间超过我正在编写的应用程序的潜在生命周期,因此,我只需用枚举“状态”标记记录这是“活动”或“已删除”。您可以从 UI 中删除某些内容,它会显示“联系人已被删除”,但应用程序所做的只是将联系人的状态更改为“已删除”,并且当应用程序调用存储库以获取联系人列表时,我会过滤在将数据推送到客户端应用程序之前删除已删除的记录。

因此, db.collection.find().count() + 1 对我来说是一个完美的解决方案......

它不适用于所有人,但如果您不删除数据,它就可以正常工作。

于 2017-04-29T12:33:35.677 回答
1

我有一个类似的问题,即我对生成唯一编号感兴趣,它可以用作标识符,但不是必须的。我想出了以下解决方案。首先初始化集合:

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 没有其他一些解决方案可能遭受的与并发环境相关的弱点。

于 2019-11-21T12:13:03.350 回答
0

应添加第一条记录

"_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;

    }
 }
于 2019-01-03T08:12:10.357 回答
0

我发现达到我的目的的最佳方法是从字段中的最大值递增,为此,我使用了以下语法:

maxObj = db.CollectionName.aggregate([
  {
    $group : { _id: '$item', maxValue: { $max: '$fieldName' } } 
  }
];
fieldNextValue = maxObj.maxValue + 1;

$fieldName是您的字段的名称,但没有$符号。

CollectionName是您的收藏的名称。

我不使用的原因count()是产生的价值可以满足现有价值。

创建强制唯一索引可以使其更安全:

db.CollectionName.createIndex( { "fieldName": 1 }, { unique: true } )
于 2019-11-08T13:24:35.887 回答
0
// await collection.insertOne({ autoIncrementId: 1 });
const { value: { autoIncrementId } } = await collection.findOneAndUpdate(
  { autoIncrementId: { $exists: true } },
  {
    $inc: { autoIncrementId: 1 },
  },
);
return collection.insertOne({ id: autoIncrementId, ...data });
于 2021-09-13T01:21:18.893 回答
-1

这可能是另一种方法

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);
于 2021-05-20T18:23:27.247 回答