【问题标题】:Unique int _id for MongoDBMongoDB 的唯一 int _id
【发布时间】:2020-02-16 03:17:27
【问题描述】:

我正在尝试为 _id 分配唯一的 int。我知道 ObjectID 是一个不错的选择,但在我的情况下我需要使用 int 作为 ID。我正在使用 Random 生成随机 int 来为其分配新对象。

这是错误:

Exception in thread "main" com.mongodb.MongoWriteException: E11000 duplicate key error 
collection: TOP100SongsUK.artists index: _id_ dup key: { _id: 484624875 }

但事实并非如此。目前,我的收藏有一些记录,这是不可能的。什么可能是触发此问题的原因?

这是写入数据库的方法,最后一个方法分配一个 ID。

 public boolean add(Artist artist) {
    Document artistToInsert = new Document();
    artistToInsert.append(ARTIST_ID, assignArtistID()).append(ARTIST_NAME, artist.getName());
    boolean validOperation = false;
    int attempts = 0;
    do {
        try {
            addArtist(artistToInsert);
            validOperation = true;
        } catch (DuplicateKeyException e) {
            attempts++;
            System.out.println("Incorrect ID for Artist");
        }
    } while (!validOperation || attempts < 3);
    if (attempts == 3) {
        throw new RuntimeException("Unable to add Artist - Mongo");
    }
    return true;
}

private boolean addArtist(Document artistToInsert) {
    artistCollection.insertOne(artistToInsert);
    return true;
}

private static Random intGenerator = new Random();
 private int assignArtistID() {
        return Math.abs(intGenerator.nextInt());
}

更新:getNextSequence 函数:

static final String ID_PARAM = "idParam";
static final String ID_SEQ = "seq";

static int getNextSequence(MongoCollection<Document> collection){
    Document findRequest = new Document();
    findRequest.append("_id", ID_PARAM);
    Document updateRequest =  new Document();
    updateRequest.append("$inc", new Document(ID_SEQ,1));
    FindOneAndUpdateOptions options = new FindOneAndUpdateOptions();
    options.upsert(true);
    options.returnDocument(ReturnDocument.AFTER);
    Document returnDoc =  collection.findOneAndUpdate(findRequest,updateRequest,options);
    return (int) returnDoc.get(ID_SEQ);
}

【问题讨论】:

标签: java mongodb


【解决方案1】:

使用随机 int 来生成 _id mongo 不是一个好主意。 您应该使用 Mongo 使用自动递增序列。

您必须使用 sequenceName 和您的 sequenceNumber 为您的序列创建一个集合。 然后对于每个插入,获取您的序列,并增加它。

这里有一些链接可以帮助您:

【讨论】:

  • 谢谢!我实施了解决方案,尽管我仍然得到 MongoWriteException: E11000 duplicate key error collection。但是这个 _id 在 DB 100% 中不存在。会不会是收藏设置的问题?即 autoIndexId: true - 我知道现在不可能从 4.0 版本开始将其更改为 false (如果您需要参考 getNextSequence() ,我在最后更新了帖子)
  • 您确定您的重复密钥错误来自您的_id?您是否在您的收藏中设置了其他索引?你能检查一下 db.collection.getIndexes() 吗?
  • 没有创建其他索引。这是完整的错误信息:E11000 重复键错误集合:TOP100SongsUK.artists 索引:id dup key: { _id: 3 } 这是 getIndexes() 的输出。 [ {“v”:2,“key”:{“_id”:1},“name”:“_id _”,“ns”:“TOP100SongsUK.artists”}]
  • 好的,谢谢。当您在 { _id: 3 } 上收到重复键错误时,您的集合中没有任何带有 _id: 3 的文档?
  • 是的,集合中没有 {_id: 3}。更有趣的是它仍然将记录插入到集合中,然后我得到一个异常。如果我吞下异常,它会按预期工作,正确添加新记录而没有任何重复
【解决方案2】:

问题在于代码本身,而不是自动递增序列。循环正在进行第二次迭代,因此插入 Object 的方法被调用了两次,但两种情况下的 ID 都是相同的。

第一次调用使用正确递增的 _id 写入 db,但循环没有中断。因此,具有相同 id 的同一对象正在写入 db,这导致了 WriteMongoException。

我删除了一个循环,效果很好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多