【问题标题】:Insert a document while auto incrementing a sequence field in MongoDB在 MongoDB 中自动递增序列字段时插入文档
【发布时间】:2018-03-26 21:03:35
【问题描述】:

问题陈述:

我在 MongoDB 中有一个集合,其中包含一个 Int32 类型的字段。我想在这个集合中添加一个文档。我需要为每个插入将值增加 1,因为该字段已编入索引并且必须是唯一的。

选项:

  1. [preferable] 增加 DB 端的值。也就是说,不指定新的(更高的)值。只需指示 MongoDB 在插入时自动递增。
  2. 先阅读。对数据库执行查找查询以首先查找当前(插入之前)最高值,在内存中递增,然后插入新文档。这可能会由于竞速条件而失败(操作不是原子的)。
  3. 在内存中保留一个索引计数器。对我来说不是一个选择,因为有多个应用程序写入同一个集合(旧限制)。
  4. 其他想法?

示例:

{
    _id: ....
    index: 123,
    open: true
}

 await collection.InsertOneAsync(record.ToBsonDocument());

插入的新文档的索引值应为 124

语言:

C#

问题:

您能否提供一个示例代码(C#)来实现第一个选项?

额外信息:

我无权访问其他应用程序的代码(该应用程序保留自己的索引号)。因此,拥有另一个集合并添加序列解析器功能将不起作用,因为这会触发对旧版应用程序的更改。

【问题讨论】:

    标签: c# mongodb


    【解决方案1】:

    MongoDB 有一个关于如何实现的默认教程here

    1 - 创建一个计数器集合并在其中插入 id:

    db.counters.insert(
       {
          _id: "userid",
          seq: 0
       }
    )
    

    2 - 创建一个自定义函数来检索下一个值:

    function getNextSequence(name) {
       var ret = db.counters.findAndModify(
              {
                query: { _id: name },
                update: { $inc: { seq: 1 } },
                new: true
              }
       );
    
       return ret.seq;
    }
    

    使用getNextSequence 检索下一个值:

    db.users.insert(
       {
         _id: getNextSequence("userid"),
         name: "Sarah C."
       }
    )
    
    db.users.insert(
       {
         _id: getNextSequence("userid"),
         name: "Bob D."
       }
    )
    

    【讨论】:

    • 谢谢。这基本上是选项#2。哪个不太有利
    • 这是服务器端操作,它原子
    • 回顾提供的答案,我现在看到它确实满足原子性。我急忙将其驳回。我很抱歉。我想请教 C# 代码,以便我们可以标记为完成。提前致谢
    • 虽然,我不确定您的 C# 实现,但是 here 是一种您可以使用 command 执行函数并获得结果的方式,您可以将其用作 insert 的一部分查询。
    【解决方案2】:

    我必须在使用 MongoDB C# 驱动程序的项目中执行此操作。

    这就是我所做的:我创建了一个名为 Sequence 的单独集合,包含它的名称和值,我还为它创建了一个存储库。

    这是Sequence类的代码:

    public class Sequence
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        [BsonElement("_id")]
        public string Id { get; set; }
    
        public string SequenceName { get; set; }
    
        public int SequenceValue { get; set; }
    }
    

    现在是生成序列值的方法代码:

    public class SequenceRepository
    {
        protected readonly IMongoDatabase _database;
        protected readonly IMongoCollection<Sequence> _collection;
    
        public SequenceRepository(IMongoDatabase database)
        {
            _database = database;
            _colecao = _database.GetCollection<Sequence>(typeof(Sequence).Name);
        }
    
        public int GetSequenceValue(string sequenceName)
        {
            var filter = Builders<Sequence>.Filter.Eq(s => s.SequenceName, sequenceName);
            var update = Builders<Sequence>.Update.Inc(s => s.SequenceValue , 1);
    
            var result = _colecao.FindOneAndUpdate(filter, update, new FindOneAndUpdateOptions<Sequence, Sequence> { IsUpsert = true, ReturnDocument = ReturnDocument.After });
    
            return result.SequenceValue;
        }
    }
    

    最后我在插入一些文档之前调用了这个方法:

    public void Inserir(Order order)
    {
        order.Code = new SequenceRepository(_database).GetSequenceValue("orderSequence");
    
        _collection.InsertOne(order);
    }
    

    【讨论】:

    • 谢谢。这基本上是选项#2吗?这在并发环境中可能不起作用。你同意吗?
    • 你需要使用 IClientSession 来控制并发
    【解决方案3】:

    您可以在单独的集合中创建 Mongo 序列 counter

    db.counter.insert({ _id: "mySeq", seq: 0 })
    

    你可以像这样将序列逻辑封装在一个简单的function

    function getNextMySeq(name) {
        var ret = db.counter.findAndModify({
            query: { _id: name },
            update: { $inc: { seq: 1 } },
            new: true
        });
        return ret.seq;
    }
    

    现在只需在插入期间使用函数调用

    db.collection.insert({
      index: getNextMySeq("mySeq") 
    })
    

    【讨论】:

    • 谢谢。这基本上是选项#2。哪个不太有利。
    • 回顾提供的答案,我现在看到它确实满足原子性。我急忙将其驳回。我很抱歉。我想请教 C# 代码,以便我们可以标记为完成。提前致谢
    猜你喜欢
    • 2014-12-25
    • 1970-01-01
    • 2013-11-18
    • 2018-08-26
    • 2014-09-09
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 2020-10-02
    相关资源
    最近更新 更多