Автоматическое увеличение номера документа в 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();
});
});
обратите внимание, что с помощью этого метода нет никакого способа потребовать числовой путь в схеме, и нет никакого смысла, потому что он автоматически добавляется.
вы можете достичь этого через:
- создать генератор последовательности, что является еще одним документом, в котором хранится счетчик последнего числа.
- использовать промежуточное ПО мангуста обновить авто инкремент нужные поля.
вот рабочий и протестированный пример с приложением 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
раз.