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

时间:2013-01-22 08:23:56

标签: mongodb mongoose

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

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

我意识到,当同时创建2个文档时,它们将获得完全相同的数字,因为我在保存文档后刚刚在设置中递增序列号。但是我在创建(不保存)文档时分配序列号,因此两个文档的序列号将完全相同。

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

如何确保此号码是唯一的并自动递增/生成?

4 个答案:

答案 0 :(得分:11)

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

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();
  });
});

请注意,使用此方法无法在架构中要求数字路径,也没有任何意义,因为它会自动添加。

答案 1 :(得分:3)

您可以通过以下方式实现这一目标:

  1. 创建序列生成器,这是另一个保留最后一个数字的计数器的文档。
  2. 使用 mongoose middleware 更新所需字段的自动增量。
  3. 这是一个使用todo app的工作和测试示例。

    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);
    

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

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

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

答案 2 :(得分:2)

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

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;
}

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

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

答案 3 :(得分:2)

您可以按如下方式使用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);

您只需要初始化autoIncrement一次。