Автоматическое увеличение номера документа в Mongo / Mongoose

мое приложение имеет несколько пользователей, каждый пользователь имеет документы. Каждый из документов должен иметь порядковый номер, который может выглядеть примерно так: 2013-1, 2013-2 (год и порядковый номер), или, возможно, просто номер: 1, 2, 3...

В настоящее время я назначаю порядковый номер из настроек пользователя, когда создается Mongoose docuemnt. Основываясь на этом порядковом номере и числовом формате из настроек пользователя, я генерирую окончательный номер документа.

Что Я реализовано, что когда 2 документа создаются одновременно, они получат точно такое же число, потому что я увеличиваю порядковый номер в настройках сразу после сохранения документа. Но я назначаю порядковый номер при создании (еще не сохранении) документа, поэтому порядковый номер будет точно таким же для обоих документов.

Мне, очевидно, нужен способ обработки этого порядкового номера автоматически увеличивающегося в момент сохранения...

Как я могу убедитесь, что это число уникально и автоматически увеличивается/генерируется?

4 ответов


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

обратите внимание, что с помощью этого метода нет никакого способа потребовать числовой путь в схеме, и нет никакого смысла, потому что он автоматически добавляется.


вы можете достичь этого через:

  1. создать генератор последовательности, что является еще одним документом, в котором хранится счетчик последнего числа.
  2. использовать промежуточное ПО мангуста обновить авто инкремент нужные поля.

вот рабочий и протестированный пример с приложением 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);

Вы можете проверить это в консоли узла следующим образом

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

С каждым вновь созданным объект вы увидите, что приоритет увеличивается. Ура!


этот код взят из 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;
}

в этом примере F-это поле в документе что вы хотите автоматически увеличивать. Чтобы сделать эту работу, вам нужно сделать свое поле уникальным, что можно сделать с помощью индексов.

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

можно использовать 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 раз.