mongodb 在 Mongo / Mongoose 中自动增加文档编号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14454271/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 13:00:58  来源:igfitidea点击:

Auto increment document number in Mongo / Mongoose

mongodbmongoose

提问by ragulka

My app has several users, each user has documents. Each documents needs to have a sequence number, that may look something like this: 2013-1, 2013-2 (year and sequence number), or perhaps just a simple number: 1, 2, 3...

我的应用程序有多个用户,每个用户都有文档。每个文档都需要有一个序列号,可能看起来像这样:2013-1、2013-2(年份和序列号),或者可能只是一个简单的数字:1、2、3...

Currently, I am assigning the sequence number from user's settings when the Mongoose docuemnt is created. Based on that sequence number and the number format from user's settings, I am generating the final document number.

目前,我正在创建 Mongoose 文档时从用户设置中分配序列号。根据该序列号和用户设置中的数字格式,我正在生成最终的文档编号。

What I realized is that when 2 documents are created at the same time, they will get exactly the same number, because I am incrementing the sequence number in settings just after I have saved a document. But I am assigning the sequence number when I am creating (not saving yet) the document so the sequence number will be exactly the same for both documents.

我意识到当同时创建 2 个文档时,它们将获得完全相同的编号,因为我在保存文档后立即增加了设置中的序列号。但是我在创建(尚未保存)文档时分配了序列号,因此两个文档的序列号将完全相同。

I obviously need a way to handle this sequence number auto-incrementing at the moment of saving...

我显然需要一种在保存时处理此序列号自动递增的方法......

How can I assure that this number is unique and automatically incremented/generated?

我如何确保这个数字是唯一的并自动递增/生成?

回答by ragulka

@emre and @WiredPraire pointed me to the right direction, but I wanted to provide a full Mongoose-compatible answer to my question. I ended up with the following solution:

@emre 和 @WiredPraire 为我指明了正确的方向,但我想为我的问题提供一个完整的猫鼬兼容答案。我最终得到了以下解决方案:

var Settings = new Schema({
  nextSeqNumber: { type: Number, default: 1 }
});

var Document = new Schema({
  _userId: { type: Schema.Types.ObjectId, ref: "User" },
  number: { type: String }
});

// Create a compound unique index over _userId and document number
Document.index({ "_userId": 1, "number": 1 }, { unique: true });

// I make sure this is the last pre-save middleware (just in case)
Document.pre('save', function(next) {
  var doc = this;
  // You have to know the settings_id, for me, I store it in memory: app.current.settings.id
  Settings.findByIdAndUpdate( settings_id, { $inc: { nextSeqNumber: 1 } }, function (err, settings) {
    if (err) next(err);
    doc.number = settings.nextSeqNumber - 1; // substract 1 because I need the 'current' sequence number, not the next
    next();
  });
});

Please note that with this method there is no way to require the number path in the schema, and there is no point as well, because it is automatically added.

请注意,使用此方法无法要求模式中的数字路径,也没有意义,因为它是自动添加的。

回答by Adrian

You can achieve that through:

您可以通过以下方式实现:

  1. create sequence generator, which is just another document that keeps a counter of the last number.
  2. Use a mongoose middlewareto update the auto increment the desired field.
  1. 创建序列生成器,它只是另一个保留最后一个数字的计数器的文档。
  2. 使用猫鼬中间件更新所需字段的自动增量。

Here is a working and tested example with the todo app.

这是一个使用 todo 应用程序的工作和测试示例。

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todoApp');

// Create a sequence
function sequenceGenerator(name){
  var SequenceSchema, Sequence;

  SequenceSchema = new mongoose.Schema({
    nextSeqNumber: { type: Number, default: 1 }
  });

  Sequence = mongoose.model(name + 'Seq', SequenceSchema);

  return {
    next: function(callback){
      Sequence.find(function(err, data){
        if(err){ throw(err); }

        if(data.length < 1){
          // create if doesn't exist create and return first
          Sequence.create({}, function(err, seq){
            if(err) { throw(err); }
            callback(seq.nextSeqNumber);
          });
        } else {
          // update sequence and return next
          Sequence.findByIdAndUpdate(data[0]._id, { $inc: { nextSeqNumber: 1 } }, function(err, seq){
            if(err) { throw(err); }
            callback(seq.nextSeqNumber);
          });
        }
      });
    }
  };
}

// sequence instance
var sequence = sequenceGenerator('todo');

var TodoSchema = new mongoose.Schema({
  name: String,
  completed: Boolean,
  priority: Number,
  note: { type: String, default: '' },
  updated_at: { type: Date, default: Date.now }
});

TodoSchema.pre('save', function(next){
  var doc = this;
  // get the next sequence
  sequence.next(function(nextSeq){
    doc.priority = nextSeq;
    next();
  });
});

var Todo = mongoose.model('Todo', TodoSchema);

You can test it out in the node console as follows

您可以在节点控制台中进行测试,如下所示

function cb(err, data){ console.log(err, data); }
Todo.create({name: 'hola'}, cb);
Todo.find(cb);

With every newly created object the you will see the priority increasing. Cheers!

对于每个新创建的对象,您将看到优先级增加。干杯!

回答by moorara

You can use mongoose-auto-incrementpackage as follows:

您可以mongoose-auto-increment按如下方式使用包:

var mongoose      = require('mongoose');
var autoIncrement = require('mongoose-auto-increment');

/* connect to your database here */

/* define your DocumentSchema here */

autoIncrement.initialize(mongoose.connection);
DocumentSchema.plugin(autoIncrement.plugin, 'Document');
var Document = mongoose.model('Document', DocumentSchema);

You only need to initialize the autoIncrementonce.

您只需要初始化autoIncrement一次。

回答by emre nevayeshirazi

This code is taken from MongoDBmanual and it actually describes making the _id field auto increment. However, it can be applied to any field. What you want is to check whether the inserted value exists in database just after you inserted your document. If it is allready inserted, re increment the value then try to insert again. This way you can detect dublicate values and re-increment them.

此代码取自MongoDB手册,它实际上描述了使 _id 字段自动递增。但是,它可以应用于任何领域。您想要的是在插入文档后检查插入的值是否存在于数据库中。如果已经插入,重新增加值,然后再次尝试插入。通过这种方式,您可以检测重复值并重新增加它们。

while (1) {

    var cursor = targetCollection.find( {}, { f: 1 } ).sort( { f: -1 } ).limit(1);

    var seq = cursor.hasNext() ? cursor.next().f + 1 : 1;

    doc.f = seq;

    targetCollection.insert(doc);

    var err = db.getLastErrorObj();

    if( err && err.code ) {
        if( err.code == 11000 /* dup key */ )
            continue;
        else
            print( "unexpected error inserting data: " + tojson( err ) );
    }

    break;
}

In this example f is the field in your document that you want to auto increment. To make this work you need to make your field UNIQUE which can be done with indexes.

在此示例中, f 是文档中要自动递增的字段。要完成这项工作,您需要使您的字段 UNIQUE 可以使用索引完成。

db.myCollection.ensureIndex( { "f": 1 }, { unique: true } )