javascript - create - Incremento automático de mangosta
mongoose js increment (12)
De acuerdo con este artículo de mongodb , es posible incrementar automáticamente un campo y me gustaría usar la forma de recolección de contadores.
El problema con ese ejemplo es que no tengo miles de personas escribiendo los datos en la base de datos usando la consola mongo. En cambio, estoy tratando de usar mangosta.
Entonces mi esquema se ve así:
var entitySchema = mongoose.Schema({
testvalue:{type:String,default:function getNextSequence() {
console.log(''what is this:'',mongoose);//this is mongoose
var ret = db.counters.findAndModify({
query: { _id:''entityId'' },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
}
});
Creé la colección de contadores en la misma base de datos y agregué una página con el _id de ''entityId''. Desde aquí no estoy seguro de cómo usar mangosta para actualizar esa página y obtener el número creciente.
No hay un esquema para los contadores y me gustaría que permanezca así porque esta no es realmente una entidad utilizada por la aplicación. Solo debe usarse en los esquemas para aumentar automáticamente los campos.
Aquí hay un ejemplo de cómo puede implementar el campo de incremento automático en Mongoose:
var CounterSchema = Schema({
_id: {type: String, required: true},
seq: { type: Number, default: 0 }
});
var counter = mongoose.model(''counter'', CounterSchema);
var entitySchema = mongoose.Schema({
testvalue: {type: String}
});
entitySchema.pre(''save'', function(next) {
var doc = this;
counter.findByIdAndUpdate({_id: ''entityId''}, {$inc: { seq: 1} }, function(error, counter) {
if(error)
return next(error);
doc.testvalue = counter.seq;
next();
});
});
Aquí hay una propuesta.
Crear una colección separada para contener el valor máximo para una colección de modelo
const autoIncrementSchema = new Schema({ name: String, seq: { type: Number, default: 0 } }); const AutoIncrement = mongoose.model(''AutoIncrement'', autoIncrementSchema);
Ahora para cada
esquema
necesario, agregue un
pre-save hook
.
Por ejemplo, deje que el nombre de la colección sea
Test
schema.pre(''save'', function preSave(next) { const doc = this; if (doc.isNew) { const nextSeq = AutoIncrement.findOneAndUpdate( { name: ''Test'' }, { $inc: { seq: 1 } }, { new: true, upsert: true } ); nextSeq .then(nextValue => doc[autoIncrementableField] = nextValue) .then(next); } else next(); }
Como
findOneAndUpdate
es una operación
atomic
, no hay dos actualizaciones que devuelvan el mismo valor de
seq
.
Por lo tanto, cada una de sus inserciones obtendrá una secuencia incremental
independientemente del número de inserciones concurrentes
.
Además, esto se puede extender a una lógica incremental automática más compleja y la secuencia de incremento automático no se limita al tipo de
número
Este no es un código probado.
Prueba antes de usar hasta que haga un complemento para
mongoose
.
Actualización Encontré que este complemento implementó un enfoque relacionado.
Combiné todas las partes buenas (subjetiva y objetivamente) de las respuestas y se me ocurrió este código:
const counterSchema = new mongoose.Schema({ _id: { type: String, required: true, }, seq: { type: Number, default: 0, }, }); // Add a static "increment" method to the Model // It will recieve the collection name for which to increment and return the counter value counterSchema.static(''increment'', async function(counterName) { const count = await this.findByIdAndUpdate( counterName, {$inc: {seq: 1}}, // new: return the new value // upsert: create document if it doesn''t exist {new: true, upsert: true} ); return count.seq; }); const CounterModel = mongoose.model(''Counter'', counterSchema); entitySchema.pre(''save'', async function() { // Don''t increment if this is NOT a newly created document if(!this.isNew) return; const testvalue = await CounterModel.increment(''entity''); this.testvalue = testvalue; });
Uno de los beneficios de este enfoque es que toda la lógica relacionada con el contador está separada.
Puede almacenarlo en un archivo separado y usarlo para múltiples modelos que importan el
CounterModel
.
Si va a incrementar el campo
_id
, el uso debería agregar su definición en su esquema:
const entitySchema = new mongoose.Schema({ _id: { type: Number, alias: ''id'', required: true, }, <...> });
Entonces, combinando múltiples respuestas, esto es lo que terminé usando:
counterModel.js
// Use pre middleware
entitySchema.pre(''save'', function (next) {
// Only increment when the document is new
if (this.isNew) {
entityModel.count().then(res => {
this._id = res; // Increment count
next();
});
} else {
next();
}
});
myModel.js
var mongoose = require(''mongoose'');
var Schema = mongoose.Schema;
const counterSchema = new Schema(
{
_id: {type: String, required: true},
seq: { type: Number, default: 0 }
}
);
counterSchema.index({ _id: 1, seq: 1 }, { unique: true })
const counterModel = mongoose.model(''counter'', counterSchema);
const autoIncrementModelID = function (modelName, doc, next) {
counterModel.findByIdAndUpdate( // ** Method call begins **
modelName, // The ID to find for in counters model
{ $inc: { seq: 1 } }, // The update
{ new: true, upsert: true }, // The options
function(error, counter) { // The callback
if(error) return next(error);
doc.id = counter.seq;
next();
}
); // ** Method call ends **
}
module.exports = autoIncrementModelID;
La respuesta más votada no funciona. Esta es la solución:
var CounterSchema = new mongoose.Schema({
_id: {type: String, required: true},
seq: { type: Number, default: 0 }
});
var counter = mongoose.model(''counter'', CounterSchema);
var entitySchema = mongoose.Schema({
sort: {type: String}
});
entitySchema.pre(''save'', function(next) {
var doc = this;
counter.findByIdAndUpdateAsync({_id: ''entityId''}, {$inc: { seq: 1} }, {new: true, upsert: true}).then(function(count) {
console.log("...count: "+JSON.stringify(count));
doc.sort = count.seq;
next();
})
.catch(function(error) {
console.error("counter error-> : "+error);
throw error;
});
});
Los parámetros de opciones le dan el resultado de la actualización y crea un nuevo documento si no existe. Puedes consultar mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate el documento oficial.
Y si necesita un índice ordenado, consulte este doc
Las respuestas parecen incrementar la secuencia incluso si el documento ya tiene un campo _id (ordenar, lo que sea). Este sería el caso si ''guarda'' para actualizar un documento existente. ¿No?
Si estoy en lo cierto, querrás llamar a next () si this._id! == 0
Los documentos de mangosta no son muy claros sobre esto. Si está realizando una consulta de tipo de actualización internamente, entonces no se puede llamar a pre (''guardar''.
ACLARACIÓN
Parece que el método previo ''guardar'' se llama efectivamente en las actualizaciones.
No creo que quieras incrementar tu secuencia innecesariamente. Le cuesta una consulta y desperdicia el número de secuencia.
No quería usar ningún complemento (una dependencia adicional, inicializando la conexión mongodb aparte de la que uso en server.js, etc.), así que hice un módulo adicional, puedo usarlo en cualquier esquema y incluso, estoy considerando cuando eliminas un documento de la base de datos.
module.exports = async function(model, data, next) {
// Only applies to new documents, so updating with model.save() method won''t update id
// We search for the biggest id into the documents (will search in the model, not whole db
// We limit the search to one result, in descendant order.
if(data.isNew) {
let total = await model.find().sort({id: -1}).limit(1);
data.id = total.length === 0 ? 1 : Number(total[0].id) + 1;
next();
};
};
Y cómo usarlo:
const autoincremental = require(''../modules/auto-incremental'');
Work.pre(''save'', function(next) {
autoincremental(model, this, next);
// Arguments:
// model: The model const here below
// this: The schema, the body of the document you wan to save
// next: next fn to continue
});
const model = mongoose.model(''Work'', Work);
module.exports = model;
Espero que te ayude.
(Si esto está mal, dígame. No he tenido problemas con esto, pero no soy un experto)
Otra forma es que puede usar paquetes externos proporcionados por mangosta. (Fácil de entender)
Puede usar el paquete
mongoose-auto-increment
siguiente manera:
var mongoose = require(''mongoose'');
var autoIncrement = require(''mongoose-auto-increment'');
/* connect to your database here */
/* define your CounterSchema here */
autoIncrement.initialize(mongoose.connection);
CounterSchema.plugin(autoIncrement.plugin, ''Counter'');
var Counter = mongoose.model(''Counter'', CounterSchema);
Solo necesita inicializar el
autoIncrement
una vez.
Sé que esto ya tiene muchas respuestas, pero compartiría mi solución, que es IMO breve y fácil de entender:
var mongoose = require(''mongoose'');
var Schema = mongoose.Schema;
const autoIncrementModelID = require(''./counterModel'');
const myModel = new Schema({
id: { type: Number, unique: true, min: 1 },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date },
someOtherField: { type: String }
});
myModel.pre(''save'', function (next) {
if (!this.isNew) {
next();
return;
}
autoIncrementModelID(''activities'', this, next);
});
module.exports = mongoose.model(''myModel'', myModel);
Asegúrese de que
entitySchema._id
tenga el
type:Number
.
Versión de mangosta:
5.0.1
.
Yo uso juntos @ cluny85 y @edtech. Pero no completo terminar estos problemas.
counterModel.findByIdAndUpdate({_id: ''aid''}, {$inc: { seq: 1} }, function(error,counter){
Pero en la función "pre (''save ...) luego la respuesta del contador de actualización finaliza después de guardar documento. Así que no actualizo el contador al documento.
Por favor verifique nuevamente todas las respuestas. Gracias.
Lo siento. No puedo agregar comentarios. Porque soy novato
var CounterSchema = Schema({
_id: { type: String, required: true },
seq: { type: Number, default: 0 }
});
var counter = mongoose.model(''counter'', CounterSchema);
var entitySchema = mongoose.Schema({
testvalue: { type: String }
});
entitySchema.pre(''save'', function(next) {
if (this.isNew) {
var doc = this;
counter.findByIdAndUpdate({ _id: ''entityId'' }, { $inc: { seq: 1 } }, { new: true, upsert: true })
.then(function(count) {
doc.testvalue = count.seq;
next();
})
.catch(function(error) {
throw error;
});
} else {
next();
}
});