Coder Social home page Coder Social logo

mongoose-sequence's Introduction

Mongoose sequence plugin

Build Status Coverage Status Donate npm

Hello everybody. Look, I have no more time to maintain this old library. If anybody wants to take over is very welcome and I'm available to review PRs. For the moment I have no time, no will to work on this library.

This plugin lets you create fields which autoincrement their value:

  • every time a new document is inserted in a collection
    or
  • when you explicitly want to increment them

This increment can be:

  • global: every document has a unique value for the sequence field
  • scoped: the counter depends on the value of other field(s)

Multiple counters can be set for a collection.

Migrating

From version 3 to version 4

Version 3 is now deprecated. In order to migrate to the new version the only change you need to do is to pass mongoose to the required module as explained in the requiring section.

From version 4 to version 5

An important fix about scoped counters is not backward compatible. You cannot use version 5 with scoped counters already present on your DB.

Requisites

This plugin needs mongoose version 4.0.0 or above.

Installation

npm install --save mongoose-sequence

Requiring

You must pass your DB connection instance for this plugin to work. This is needed in order to create a collection on your DB where to store increment references.

const mongoose = require('mongoose');
const AutoIncrement = require('mongoose-sequence')(mongoose);

If you use different connections you must include it this way

const mongoose = require('mongoose');
const AutoIncrementFactory = require('mongoose-sequence');

const connection = await mongoose.createConnection('mongodb://...');

const AutoIncrement = AutoIncrementFactory(connection);

Global sequences

Let's say you want to have an id field in your user collection which has a unique auto-incremented value.

The user schema is something like this:

UserSchema = mongoose.Schema({
  name: String,
});

mongoose.model('User', UserSchema);

You don't need to define the id field in your schema because the plugin automatically sets it for you. The only thing you have to do is to call:

UserSchema.plugin(AutoIncrement, { inc_field: 'id' });

after requiring the plugin.

Every time a new user is created, the id field will have an incremented number. The operation is atomic and is based on this specification. A commodity collection named counters is created for you. You can override the name of this collection but we will see this later with the options.

If you want to increment the _id field which is special to mongoose, you have to explicitly specify it as a Number and tell mongoose to not interfere:

UserSchema = mongoose.Schema(
  {
    _id: Number,
    name: String,
  },
  { _id: false },
);
UserSchema.plugin(AutoIncrement);

In this case you don't have to specify inc_field because the default value is _id

Not automatic sequences

Let's say our user model has a rank field which gives the rank of the user in a tournament. So it saves the arrival order of a user to the end of our amazing game. This field is of course a sequence but has to be incremented every time an event occurs. Because we have concurrent access to our database we want to be sure that the increment of this counter happens safely. Let's start by modifying our schema:

UserSchema = mongoose.Schema({
  name: String,
  rank: Number,
});

This time we specified explicitly the field rank. There is no difference between defining and omitting the field specification. The only constraint is that the field has to be of type Number, otherwise the plugin will raise an error. So, let's tell the plugin we want the rank field to be a safe counter:

UserSchema.plugin(AutoIncrement, { inc_field: 'rank', disable_hooks: true });

We specified disable_hooks. This avoids the field being incremented when a new document is saved. So, how to increment this field? Your models have a new method: setNext. You must specify which sequence you want to increment and a callback. Here's an example:

User.findOne({ name: 'George' }, function (err, user) {
  user.setNext('rank', function (err, user) {
    if (err) console.log('Cannot increment the rank because ', err);
  });
});

You noticed that the method setNext takes, as argument, the counter field name. It is possible to give a name to the counter and use it as reference. For the previous example we can define the counter like this:

UserSchema.plugin(AutoIncrement, {
  id: 'rank_counter',
  inc_field: 'rank',
  disable_hooks: true,
});

and then use:

user.setNext('rank_counter', function (err, user) {
  //...
});

So, if you do not specify the id, the field name is used. Even if you're not forced to specify an id, its use is strongly suggested. This is because if you have two different counters, which refers to fields with the same name, they will collide and incrementing one will increment the other too. Counters are not bound to the schema they refer to, so two counters for two different schemas can collide. So use a unique id to be sure to avoid collision. In the case of a collision the plugin will raise an error.

As we will see, the use of an id for the counter is mandatory when you're defining a scoped counter.

NOTE: When you call setNext the document is automatically saved. This behavior has changed since version 3.0.0. If you use a prior version you have to call save by yourself.

Advanced

Scoped counters

Let's say our users are organized by country and city and we want to save the inhabitant_number according to these two pieces of information.
The schema is like this:

UserSchema = mongoose.Schema({
  name: String,
  country: String,
  city: String,
  inhabitant_number: Number,
});

Every time a new Parisian is added, the count of Parisians has to be incremented. The inhabitants of New York must not interfere, and have their separate counting. We should define a scoped counter which increments the counter depending on the value of other fields.

UserSchema.plugin(AutoIncrement, {
  id: 'inhabitant_seq',
  inc_field: 'inhabitant_number',
  reference_fields: ['country', 'city'],
});

Notice that we have to use an id for our sequence, otherwise the plugin will raise an error. Now save a new user:

var user = new User({
  name: 'Patrice',
  country: 'France',
  city: 'Paris',
});
user.save();

This user will have the inhabitant_number counter set to 1. If now we add a new inhabitant from New York, this will have its counter set to 1 also, because the counter is referred to by the value of the fields country and city.

If we want to increment this counter manually we have to specify the id of the sequence in the setNext method:

user.setNext('inhabitant_seq', function (err, user) {
  user.inhabitant_number; // the counter value
});

Of course this example is a bit forced and this is for sure not the perfect use case. The fields country and city have to be present and must not change during the life of the document because no automatic hooks are set on the change of those values. But there are situations when you want a similar behavior.

Reset a counter

It's possible to programmatically reset a counter through the Model's static method counterReset(id, reference, callback). The method takes these parameters:

  • id: the counter to reset. It's mandatory
  • reference: Lets you reset only a specific reference of the counter, if the counter has referenced fields. Optional. By default it resets all the counters for the id
  • callback: A callback which receives an error in case of any. Mandatory

Some examples:

Model.counterReset('counter_id', function (err) {
  // Now the counter is 0
});

Model.counterReset('inhabitants_id', function (err) {
  // If this is a referenced field, now all the counters are 0
});

Model.counterReset(
  'inhabitants_id',
  { country: 'France', city: 'Paris' },
  function (err) {
    // If this is a referenced field, only the counter for Paris/France is 0
  },
);

Nested fields

It is possible to define a nested field as counter, using . as the path separator:

NestedSchema = new mongoose.Schema({
  name: { type: String },
  registration: {
    date: { type: Date },
    number: { type: Number },
  },
});

NestedSchema.plugin(AutoIncrement, {
  id: 'user_registration_seq',
  inc_field: 'registration.number',
});

Options

This plugin accepts the following options:

  • inc_field: The name of the field to increment. Mandatory, default is _id.
  • id: Id of the sequence. Mandatory only for scoped sequences but its use is strongly encouraged.
  • reference_fields: The field to reference for a scoped counter. Optional.
  • start_seq: The number to start the sequence from. Optional, default 1.
  • inc_amount: The quantity to increase the counter at each increment. Optional, default 1.
  • disable_hooks: If true, the counter will not be incremented on saving a new document. Default false.
  • collection_name: By default the collection name to mantain the status of the counters is counters. You can override it using this option.
  • parallel_hooks: If true, hooks will be registered as parallel. Default true.

Notes

When using insertMany the plugin won't increment the counter because the needed hooks are not called. If you need to create several documents at once, use create instead and pass an array of documents (refer to #7).

mongoose-sequence's People

Contributors

amansingh63 avatar dandv avatar dependabot[bot] avatar iagowp avatar jimmyhogoboom avatar leeqiang avatar m-ramp avatar manoellobo avatar ramiel avatar toto1384 avatar waptik avatar wyatt-troia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mongoose-sequence's Issues

Complete code modernization

  • Use functions instead of class functions
  • Use arrow-functions when possible
  • Update test code to use only jest, no sinon, no chai

Doesn't work with findOneAndUpdate

I'm using findOneAndUpdate and upsert:true to do a findOrCreate buy my auto increment field is not being populated. It works when using create.

How do i change the id of the sequence?

I want to change te id of the sequence to something that is more appropriate - how do I do this without resetting the counter?

Also, if migrating from my own previous sequence to using your package, how do I set the sequence to carry on from where it left off?

AutoIncrement is not defined

Hey, I just tried to install this on my project, but I'm getting this error
ReferenceError: AutoIncrement is not defined

I only added this line of code after adding it to the project.
UserSchema.plugin(AutoIncrement, {inc_field: 'id'});

Is there something else that needs to be done that isn't mentioned?

Multiple increment field

Is it possible to use this plugin on several fields ?

Because the documentation said It's possible, but there is not example to achieve that.

Thanks for any help

Reset to specific value or decrement method

Sometimes a model object that I use the incrementer for gets deleted. Once that happens, I would like to decrement the counter again or to reset it to the value before.

Would this feature be possible to add? Otherwise you have to directly manipulate the collection as a workaround.

Ever tested on AWS Elastic Beanstalk ?

Hi,

I wrote a very simple Node Express Mongoose Application (just one model)
Everything works fine on my local machine.

Though, as soon as I deploy to AWS Elastic Beanstalk, the App doesn't work ...

When I comment the lines

const AutoIncrement = require('mongoose-sequence')(mongoose);

and

userSchema.plugin(AutoIncrement, {
  id: 'userAutoInc',
  inc_field: 'ID'
});

and I re-deploy, my App works fine again (though, of course; without an Autnumber field.

So, after half a day "debugging by elimination", I think I can conclude your module is giving a small problem on AWS...

Health of the server changes to DEGRADED, which results in a 502 error ... (i.e. application is not running on the server, due to the fact the compilation failed...)

I'm using a MongoDB on Atlas...

I THINK (though, I might be wrong), that for one reason or another, your module isn't able to create the collection "counters" ... (but once again, that's just a wild guess)

Any help would be more than welcome, cause we really LIKE your module !!
And I'm certainly willing to do some tests for you.

Thanks in advance for your reply,

Johnny Driesen
Belgium

Multiple counters with same inc_field but different id

Hi There,

It seems multiple counters doesn't work in situation like this:
collection A:
SchemaA.plugin(AutoIncrement, {inc_field: 'seq', id: "aSeq"});

collection B:
SchemaB.plugin(AutoIncrement, {inc_field: 'seq', id: "bSeq"});

right now both collections share a "seq" counter.

I read the source code and it seems the issue is from:

if (_.isNull(options.reference_fields)) {
      **// here it should use options.id after options.id is set** 
       options.reference_fields = options.inc_field; 
       this._useReference = false;
    } else {
        this._useReference = true;
    }

Can you help take a look and see if this is a bug or expected results?

Thanks,
Ke

Scoped singleton archive

Hi, thanks for the module, I've an issue regarding to differents DB with the same sequence.

Reading your code I could check your archive lib is defined at the beginning of your code, instead of do it in the getInstance method so if you have two DB with the same sequence it return error.

Can you fix it please? It's just move the definition fron the top to inside the getInstance method.

Thanks in advance

Auto increment id don't work with Model.insertMany

Hi guys, as title, has anyone got this issue like me ?

I have a productSchema and plugged autoIncrement

const productSchema = new Schema({
    _id: Number,
    // ...
})
productSchema.plugin(autoIncrement, {inc_field:'_id'})
const Product = db.model('product', productSchema, 'product_new');

Use .save it works well, _Id field value is a Number

jsonProduct = {...}
let product = new Product(jsonProduct)
    product.save(function (err, product) {
      if (err) return console.error(err);
      db.connection.close()
});

Use .insertMany, _id field is ObjectID not a Number

jsonProducts = [{...},{...}...]
Product.insertMany(jsonProducts, function (err, product) {
      if (err) return console.error(err);
      db.connection.close()
});

is it possible to make a populate?

I am trying to replace the _id of a collection and use it as a reference in another schema. But I could not make a populate since the second collection. It's possible?

Hang

Hi, the following program hangs in the call to collection.create(). Not sure what I am doing wrong. It "works" if uncommenting the line with AutoIncrement:

/*
  "dependencies": {
    "mongoose": "^5.5.15",
    "mongoose-sequence": "^5.0.1"
  }
*/
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const AutoIncrement = require('mongoose-sequence')(mongoose);

const TestSchema = new Schema({
    subject: { type: String, required: true },
});

TestSchema.plugin(AutoIncrement, { inc_field: 'testCode' } );

async function oo() {
    const client = await mongoose.createConnection('mongodb://localhost/MONGOOSESEQUENCE');
    const collection = client.model('test', TestSchema);
    // Never returns:
    const result = await collection.create([{
        subject: "subject",
    }]);

    await client.close();
}

oo();

.save() callback not being called when using plugin

The callback from the .save(callback) function of the model does not get called.

I followed the reference for the scoped usage.

No errors are seen,

using:
"mongoose": "^4.3.4",
"mongoose-sequence": "^3.1.0",

How to do a populate?

Hello and thanks!

I was wondering and headbanging how to do a populate query:

I am trying to use IDs for relationships...
example: a client = { name: 'Name', providers: [1,2,3,5]}
I can save clients like that but can't retrieve them

const ClientSchema = new mongoose.Schema({
    name: {type: String},
    providers: [{ type: Number, ref: 'Provider' }], 
});
ClientSchema.plugin(AutoIncrement, { id: 'clientId', inc_field: 'id'}); // reference_fields ???

const ProviderSchema = new mongoose.Schema({
    name: {type: String},
});
ProviderSchema.plugin(AutoIncrement, {id: 'providerId', inc_field: 'id'});

return Promise.all([
        Client.find()
            .populate('providers') // Here
            .exec(),
        Client.count(query).exec(),
    ]).then(function (results) {

Cast to ObjectId failed for value "1" at path "_id" for model "Provider"

Many thanks

Reset increment

Hello, ty for ur amazing plugin.
Help me please.
I'm need to reset counter, i'm try drop collection but it's not slove my problem

use same counter (shared counter) for multiple schemas

Suppose I have 2 schemas:

let sch1 = new Schema({
    _id: Number
})

let  sch2 = new Schema({
    _id: Number
})

I need to use same counter (same sequence) for both schemas

So, I expected to write the following code:

sch1.Plugin(AutoIncrement, {id: 'mySharedCounter'})
sch2.Plugin(AutoIncrement, {id: 'mySharedCounter'})

But the program crashes with the following error

Counter already defined for field "mySharedCounter"
at Sequence.getInstance (D:\PROJECTS\golden\node_modules\mongoose-sequence\lib\sequence.js:69:15)
at Schema.plugin (D:\PROJECTS\golden\node_modules\mongoose\lib\schema.js:1198:3)

Not sure but I believe that the behavior should be: "If the counter already exists, use that counter". Or maybe create a new option (perhaps useSharedCounter: true //default false
So the library not throw error if there's already a counter with same name if useSharedCounter=true

Then I write the following code:

sch1.Plugin(AutoIncrement, {id: 'mySharedCounter', useSharedCounter: true})
sch2.Plugin(AutoIncrement, {id: 'mySharedCounter', useSharedCounter: true})

Counter reset how to

@ramiel

hi,

I am using you plugin and I am delighted on the way it works and solve my requirements so far.

I have the following use of your plugin

const AutoIncrement = autoincrement(mongoose);

EmployeeSchema.plugin( AutoIncrement, { id: 'employees_counter', inc_field: 'sequence', reference_fields: ['customer', 'establishment'] } );

export const Employee: Model<IEmployeeModel> = model<IEmployeeModel>("Employee", EmployeeSchema);

This works fine and keeps separate counters for employee per company/establishment.

Now I have the need to reset some scoped counters when a user deletes all the documents that are in the scope ( ie the HR manager wants to rebuild its employees list from scratch ) and so I am trying to implement the resetCounter static method.

None of my tentative have been successful so far as the method is never found anywhere.

In your documentation you say Model.counterReset( id, reference, callback);

Looking into your code, I am assuming that the model you are referring to is in my case Employee as

this._schema.static('counterReset', function(id, reference, callback) {
        var sequence = sequenceArchive.getSequence(id);
        sequence._resetCounter(id, reference, callback);
    }.bind(this));

but when I try to execute Employee.counterReset ( 'employees_counter', { customer: 'xxx', establishment: 'yyy' }, errorHandler( err) )

I get an error saying that the method counterReset does not exists ...

What am I doing wrong ?

Thanks for your help

Auto-increment has been done in case of document conflict

I have a collection with lets say X auto increment field and which has also compound unique index. So in case of duplication of fields save method returns 409 error, but X field has been incremented.
The expected behavior would be to increment X field only when document is saved in the collection.

DeprecationWarning

(node:84409) DeprecationWarning: collection.findAndModify is deprecated. Use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead.

My mongoose version is v5.4.6.

Parallel or Sequential Behavior Should be Optional

When trying to access the sequence number generated by this plugin in the next middleware (another plugin or pre-save hook) you may encounter an invalid value because of this middleware registering as a parallel hook. (See here)

I suggest to add an additional configuration variable to change this behavior when the user wants this plugin to act sequential.

.save() doesn't work with Mocha

mongodb 3.4.6
mongoose 4.11.7
mongoose-sequence 4.0.0

models/Product.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const AutoIncrement = require('mongoose-sequence')(mongoose);

const ProductSchema = new Schema({
    _id: Number,
    name: String,
    image: String,
    price: Number,
    count: Number,
    discount: Number,
    removed: Number
}, { _id: false });

ProductSchema.plugin(AutoIncrement, { id: 'product' });

module.exports = mongoose.model('product', ProductSchema);

test/test_helper.js

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/tests', { useMongoClient: true });
mongoose.connection
    .once('open', () => console.log('Connected :)'))
    .on('error', err => console.log('Error:', err));

test/products_test.js

const Product = require('../models/product');

describe('Products', () => {
    it('creates a product', () => {
        let product = new Product({
            name: 'Apple'
        });

        product.save(() => {
            console.log('You\'ll never see me :(');
        });
    });
});

Same field name in different schemes

Hello, I'd like to add the same field (internalCode) in two different schemes, but it throws "Counter already defined for field "internalCode"". How could I resolve it? I really need the same name.

Using a nested field as inc_field

Is it possible to use a nested field as inc_field?

Considering a Schema like

const Schema = new mongoose.Schema({
  prop1: {type: Number},
  // ...
  propN: {
    date: {type: Date},
    fieldToInc: {type: Number}
  }
})

how would I implement the sequence to propN.fieldToInc?

Something like

Schema.plugin(Sequence, {
  id: 'nested_seq',
  inc_field: 'propN.fieldToInc' // not working, just an example
  // ...
})

By the way, thank you very much for this awesome library!

Scoped counter with more than one reference counter fails with duplicate key

I have the requirement to keep unique sequence counter per establishment per company in an employee document.

I have specified the following using your plugin :

EmployeeSchema.plugin( AutoIncrement, { id: 'employees_counter', inc_field: 'sequence', reference_fields: ['customer', 'establishment'] } );

Inserting multiple documents with customer = '5c5498941f17864d225d18d4' and establishement = '85520050700017' works just fine a document is created in the Counters document with the following values.

{"_id":"5c5f23e0114925934b3a53b7",
   "id":"employees_counter",
   "reference_value":["\"5c5498941f17864d225d18d4\"","\"85520050700017\""],
   "seq":20
}

Resetting the counter works fine ( as per my previous issue ).

But when I want to insert a document that has a different a different establishement value for the same customer value, the insert is rejected with a duplicate key in the Counter

MongoError: E11000 duplicate key error collection: moncse.counters index: id_1_reference_value_1 dup key: { : "employees_counter", : ""5c5498941f17864d225d18d4"" }

I have read issue #34 and thought that the pb was fixed. It seems not.

This render you plug-in unusable for me if the pb is not fixed.

Reset Counter

Hello,

is there a way to reset the counter? I did some inserts for test and now it would be nice to reset the counter.

thanks!

Incrementing _id field special to mongoose doesn't work

I followed your guide to do this
UserSchema = mongoose.Schema({
_id: Number,
name: String
}, { _id: false });
UserSchema.plugin(AutoIncrement);

But I keep getting error that "Cast to number failed for value " {name : Michael} " at path _id for model Hotel

Adding a sequence to a schema never resolves when using save()

Without the plugin installed and configured on a schema, I can POST to my Rest API and receive a response.

With this installation, requests timeout (custom timer of 3 seconds) with no error throw while inserting a new document with model.save().

var mongooseSequence = require("mongoose-sequence");

schema.plugin(mongooseSequence, {
  id: "invoice_no",
  inc_field: "no",
  collection_name: "sequence"
});

Using the following related npms:
"mongodb": "^2.2.30",
"mongoose": "^4.11.5",
"mongoose-delete": "^0.4.0",
"mongoose-sequence": "^3.2.0",

Please note mongoose-delete is another plugin and works fine.
Also note that the sequence collection is never created (same for counters collection when option is not specified).

Scoped Counters only working with a single reference_field

Given any model wich I want to scope by two reference_fields ['fieldA','fieldB'] this would give an error of mongo duplicate key.

const mongoose = require('mongoose'),
    Schema = mongoose.Schema;

const AutoIncrement = require('mongoose-sequence')(mongoose);

const schema = new Schema(
    {
        empresa: { type: Number, required: true },
        pedido: { type: Number, required: true },
        key: Number, //sequence
    });

schema.plugin(AutoIncrement, { id: 'items', inc_field: 'key', reference_fields: ['empresa','pedido'] });
´``

This bug can be reproduced with the latest 4.0.1 version.

Error with keys using Promise.all

I'm trying to save multiple records in a single step but it ends with an error

  • model:
...
let personSchema= new mongoose.Schema({
    _id: Number,
    name: {
        type:     String,
        required: true
    }
});
personSchema.plugin(AutoIncrement);

module.exports = mongoose.model('Person', personSchema);
  • Usage
function createMultipleUsers(){
    return Promise.all([
        Person.create({name:'ivan'}),
        Person.create({name:'axel'})
   ]);
}
createMultiple();
  • Error:
E11000 duplicate key error collection: db.counters index: id_1_reference_value_1 dup key: { : "_id", : null }

_id is incremented, and my inc_field value is ignored

First, I'm using Typescript.

In my App class for an Express/Mongoose app, I have:

   private mongoose = require('mongoose');
   private autoIncrement = require('mongoose-sequence')(mongoose);

Then, in my constructor I have:

  constructor() {
    this.app = express();
    this.config();
    this.routePrv.routes(this.app);
    this.mongoSetup();

    mongoose.model('Todos', TodoSchema);

    TodoSchema.plugin(this.autoIncrement, {
      inc_field: 'todoid',
      start_seq: 422
    });
  }

This compiles and "works" in that the alpha-numeric _id field from mongoose is auto-incremented when posting via a REST API in Postman.

My todoid field doesn't exist in the resulting JSON and is completely ignored.

How do I get my todoid field to auto-increment and appear in the resulting record?

I hope this is okay to ask here.

Empty counters collection created but nothing else happens

Using Mongoose 5.3.10 and Mongoose-Sequence 4.0.1.

A counters collection is created but it is empty and Mongoose-Sequence does not seem to create or modify the inc_field. An example _id field from a new document using the below code: "_id" : ObjectId("5be9fb8f86e5f02285b59ce6").

var mongoose = require('mongoose');
const AutoIncrement = require('mongoose-sequence')(mongoose);
mongoose.connect('mongodb://localhost/topBunk');

var db = mongoose.connection;

var listingSchema = new mongoose.Schema({
  _id: Number,
  price: Number,
}, { _id: false });
listingSchema.plugin(AutoIncrement);

var Listing = mongoose.model('Listing', listingSchema);

module.exports = Listing;

I have also tried with an inc_field other than _id. Here, the inc_field of id does not appear on the created document, and _id is generated despite specifying { _id: false}.

var mongoose = require('mongoose');
const AutoIncrement = require('mongoose-sequence')(mongoose);
mongoose.connect('mongodb://localhost/topBunk');

var db = mongoose.connection;

var listingSchema = new mongoose.Schema({
  id: Number,
  price: Number,
}, { _id: false });
listingSchema.plugin(AutoIncrement, { inc_field: 'id'});

var Listing = mongoose.model('Listing', listingSchema);

module.exports = Listing;

Migrate from sql

I'm migrating an sql database so I need to keep old ids and then my new system will user auto increment starting from the last id.

I can't find a way to do this.

AWS Lambda support

If anyone wants to use this on lambda you got to change the code around 179- 180 to this

let lambdaID =Counter_${this._options.id}; if(!connection.models[lambdaID]){ return connection.model(lambdaID,CounterSchema); }else{ return connection.models[lambdaID]; }

reset counter on _id field

Hello I set the counter on _id filed following the REAME

UserSchema = mongoose.Schema({
    _id: Number,
    name: String
}, { _id: false });
UserSchema.plugin(AutoIncrement);

And reset _id as follow

Model.counterReset('counter_id', function(err) {
    // Now the counter is 0
});

However, then I delete all documents in database and save new document, the _id filed is not
reset to 0.

setNext used within a pre-save hook works but generates an error

@ramiel

hi Fabrizio

Pursuing previous exchange on scoped counter, I have the requirement in my application to manage when a counter is incremented when a new document is added.

I have seen that the setNext method is made just for this and looking at your code, I see that it invokes the same function than what you normally do in the pre-save hook that you attach to the schema in order to increment the counter for a new document.

In my case, each new document should not get a specific counter incremented.

In fact, due to legal reasons, employees documents in my application can't be updated in place. In order to keep the previous value of the document, the current document is marked as archived, a new document is created as a clone of the one just archived and changes are applied to this new document.

As employees must have a unique sequence number, the counter should not be incremented in this case. So if a value already exists in the sequence attribute the sequence number should not be set with a new value, leaving all employees documents for a specific employee with the same sequence counter value but a different updateSequence counter incremented at each update.

Here below is what I have implemented :

import { Document, Schema, Model, model} from "mongoose";

import * as autoincrement from "mongoose-sequence";
import * as mongoose from "mongoose";import { EmailSchema } from "./email.schema";

import { PhoneSchema } from "./phone.schema";
import { AddressSchema } from "./address.schema";
import { ProviderSchema } from "./provider.schema";
import { TraineeSchema } from "./trainee.schema";
import { ForeignerSchema } from "./foreigner.schema";

import { IEmployee } from "../interfaces/employee";

export interface IEmployeeDocument extends IEmployee, Document {
    setNext( id: string, callback: any ):void;
}

export interface IEmployeeModel extends Model<IEmployeeDocument> {
    counterReset( id: string, reference: any, callback: any ): void;
}

export const EmployeeSchema: Schema = new Schema({
    sequence: Number,
    customer: String,
    establishment: String,
    nir: String,
    quality: String,
    firstName: String,
    lastName: String,
    birthCountry: String,
    birthCity: String,
    birthDate: Date,
    startDate: Date,
    exitDate: Date,
    contract: String,
    duration: String,
    ratio: Number,
    category: String,
    replacing: String,
    address: AddressSchema,
    emails: [EmailSchema],
    phones: [PhoneSchema],
    idcc: String,
    citizenship: String,
    position: String,
    firingAllowance: Date,
    provider: ProviderSchema,
    foreigner: ForeignerSchema,
    trainee: TraineeSchema,
    isTrainee: Boolean,
    archived: Date,
    updateSequence: Number
}, { timestamps: true });


EmployeeSchema.pre<IEmployeeDocument>('save',  true,function (next, done ) {

        next();
        if (this.sequence) {
            return done();
        }
        this.setNext('employees_counter', (err) => {
            if ( err ) {
                console.log('Error while incrementing employees_counter', err);
            }
        });
        done();
    }
);

const AutoIncrement = autoincrement(mongoose);

EmployeeSchema.plugin( AutoIncrement, { id: 'employees_counter', inc_field: 'sequence', reference_fields: ['customer', 'establishment', 'isTrainee'] , disable_hooks: true });
EmployeeSchema.plugin( AutoIncrement, { id: 'employees_update_counter', inc_field: 'updateSequence', reference_fields: ['customer', 'establishment', 'nir'] } );

export const Employee: IEmployeeModel = model<IEmployeeDocument, IEmployeeModel>("Employee", EmployeeSchema);

Counters are well incremented as expected.

A new employees_counter value is set in the sequence attribute when a new employee is created as well as 1 in the updateSequence.

When an employee is udpated, a new document is created, the sequence remains the same and the updateSequence receive an incremented value.

So far so good.

But the rest api console displays the following message when a new employee is created :

Error while incrementing employees_counter { ParallelSaveError: Can't save() the same doc multiple times in parallel. Document: 5c6526f884611085d073b031
    at ParallelSaveError.MongooseError [as constructor] (/Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose/lib/error/mongooseError.js:13:11)
    at new ParallelSaveError (/Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose/lib/error/parallelSave.js:18:17)
    at model.Model.save (/Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose/lib/model.js:440:20)
    at model.<anonymous> (/Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose-sequence/lib/sequence.js:224:18)
    at /Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/async/dist/async.js:4617:26
    at /Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose-sequence/lib/sequence.js:269:24
    at /Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose/lib/model.js:4670:16
    at process.nextTick (/Users/rer/Documents/Private/Angular Applications/mongodb-monCSE-restful-api/node_modules/mongoose/lib/query.js:2682:28)
    at process._tickCallback (internal/process/next_tick.js:61:11)
  message:
   'Can\'t save() the same doc multiple times in parallel. Document: 5c6526f884611085d073b031',
  name: 'ParallelSaveError' }

Could it be that there might be a conflict between the automatic update of the updateSequence counter and the manual update of the sequence counter.

Am I doing something wrong ?

Custom id field index

I want to make my auto increment field (not called _id) to be an index. How can I create the index?

Plugin not working with findOneAndUpdate

mongoose function findOneAndUpdate with upsert:true allow insert new document.
If i use this mongoose function, i have one new document but with regular _id: ObjectId("xxxxxx")

Mongoose discriminator: throws [discriminator].plugin is not a function

Below mongoose code with discriminator is throwing error,

var options = { _id: false , discriminatorKey: 'studio', timestamps: {}};

Base Model:
var StudioSchema = new Schema({ _id: { type: Number }, cid: { type: String, required: true } isActive: {type: Boolean, default: true}, }, options);
var Studio = mongoose.model('Studio', StudioSchema);

With Discriminator,
var Shots = Studio.discriminator('shots', new mongoose.Schema({ shots: [{ name: { type: String }, imgs: { src: String } }] }, options ));

Trying to add mongoose sequence plugin as follows,
Shots.plugin(AutoIncrement);

It throwing error as "TypeError: Shots.plugin is not a function"

Instead If I use StudioSchema.plugin(AutoIncrement), Mongoose is throwing error as

document must have an _id before saving

how should I use it for discriminators?

Does it work atomically in cluster?

Hi,
I wonder whether if any one tested in cluster? will the configured id field value, says number, still atomically unique?

Thanks alot.

No response / hangs on Model.save (counter collection not created)

For eg: I have a schema names PostSchema. If I remove the following line, everything works just fine:

PostSchema.plugin(AutoIncrement, {inc_field: 'id'});

However, if I keep the above line, whenever I create a new PostSchema object and call it's save method, the callback is never called and since I am using this via a webserver, nothing is sent back to the request. I have also tried setting the plugin for the _id field by following relevant instructions on the README, but experienced the same problem.

Note that the counters collection was never created during this entire process. Shouldn't the plugin have done so? (Might be of interest while debugging)

Embedded document: add auto increment id does not work.

The example shows that the auto increment does not work on embedded documents.

This does not work:
The parent document implementation with mongoose-sequence
The embedded document implementation

The parent document's auto increment id does work, however when I add an auto increment id on my embedded document I get this error:
Error: Counter already defined for field "_id" at Sequence.getInstance (C:\Users\\Desktop\Programming\MonDoAPI\node_modules\mongoose-sequence\lib\sequence.js:69:15) at Schema.plugin (C:\Users\...\Desktop\Programming\MonDoAPI\node_modules\mongoose\lib\schema.js:1139:3) at Object.<anonymous> (C:\Users\...\Desktop\Programming\MonDoAPI\models\sensorModule.model.js:21:19) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) at Module.require (module.js:497:17) at require (internal/module.js:20:19) at Object.<anonymous> (C:\Users\...\Desktop\Programming\MonDoAPI\controllers\sensorModule.controller.js:1:84) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) [nodemon] app crashed - waiting for file changes before starting...

DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead

I base on Meteor, [email protected], [email protected].

// Mongoose
import Mongoose from 'mongoose'
const MongoTypes = Mongoose.Schema.Types
const AutoIncrement = require('mongoose-sequence')(Mongoose)

const Mg_EmployeesSchema = new Mongoose.Schema({
  name: String,
  birthDate: Date,
  gender: String,
  address: {
    type: String,
  },
  decimalNum: {
    type: MongoTypes.Decimal128,
  },
  floatNum: {
    type: Number,
  },
})
Mg_EmployeesSchema.plugin(AutoIncrement, { inc_field: 'id' })

export const Mg_Employees = Mongoose.model('employees', Mg_EmployeesSchema)

Get

DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead

Clustered Mode

is it safe to use this in the Cluster Mode i.e. is the increment operation is atomic. I want to use however i will getting a a very high number of writes i.e. around 200-300 per second so i need to sure that this operation will be atomic and will have no conflict. I am using mongodb 3.2.x.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.