{"id":13527152,"url":"https://github.com/ramiel/mongoose-sequence","last_synced_at":"2025-05-16T07:07:17.576Z","repository":{"id":40267397,"uuid":"43263588","full_name":"ramiel/mongoose-sequence","owner":"ramiel","description":"Sequence and autoincrement handling for mongoose","archived":false,"fork":false,"pushed_at":"2024-06-16T09:53:45.000Z","size":505,"stargazers_count":289,"open_issues_count":32,"forks_count":56,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-10T15:16:51.097Z","etag":null,"topics":["auto-increment","counter","mongodb","mongoose"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ramiel.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ramiel"}},"created_at":"2015-09-27T20:27:21.000Z","updated_at":"2025-04-09T12:40:34.000Z","dependencies_parsed_at":"2024-01-13T22:47:21.190Z","dependency_job_id":"7a2496d4-52f8-4fa2-ac7d-bedc53fa7b4c","html_url":"https://github.com/ramiel/mongoose-sequence","commit_stats":{"total_commits":106,"total_committers":14,"mean_commits":7.571428571428571,"dds":0.160377358490566,"last_synced_commit":"f8a3f10f5494bb4c9038947a9821fb5a14d2774d"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ramiel%2Fmongoose-sequence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ramiel%2Fmongoose-sequence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ramiel%2Fmongoose-sequence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ramiel%2Fmongoose-sequence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ramiel","download_url":"https://codeload.github.com/ramiel/mongoose-sequence/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485065,"owners_count":22078767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auto-increment","counter","mongodb","mongoose"],"created_at":"2024-08-01T06:01:42.166Z","updated_at":"2025-05-16T07:07:12.567Z","avatar_url":"https://github.com/ramiel.png","language":"JavaScript","readme":"# Mongoose sequence plugin\n\n[![Build Status](https://travis-ci.org/ramiel/mongoose-sequence.svg?branch=master)](https://travis-ci.org/ramiel/mongoose-sequence)\n[![Coverage Status](https://coveralls.io/repos/github/ramiel/mongoose-sequence/badge.svg?branch=master)](https://coveralls.io/github/ramiel/mongoose-sequence?branch=master)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/FabrizioRuggeri)\n![npm](https://img.shields.io/npm/v/mongoose-sequence)\n\nHello everybody. Look, I have no more time to maintain this old library. If anybody wants to take over is very welcome\nand I'm available to review PRs. For the moment I have no time, no will to work on this library.\n\nThis plugin lets you create fields which autoincrement their value:\n\n- every time a new document is inserted in a collection  \n  or\n- when you explicitly want to increment them\n\nThis increment can be:\n\n- **global**: every document has a unique value for the sequence field\n- **scoped**: the counter depends on the value of other field(s)\n\nMultiple counters can be set for a collection.\n\n## Migrating\n\n### From version 3 to version 4\n\nVersion 3 is now deprecated. In order to migrate to the new version the only change you need to do is to pass `mongoose`\nto the required module as explained in the [requiring](#requiring) section.\n\n### From version 4 to version 5\n\nAn important fix about scoped counters is not backward compatible. You cannot use version 5 with scoped counters already\npresent on your DB.\n\n## Requisites\n\nThis plugin needs mongoose version 4.0.0 or above.\n\n## Installation\n\n`npm install --save mongoose-sequence`\n\n## Requiring\n\nYou must pass your DB connection instance for this plugin to work. This is needed in order to create\na collection on your DB where to store increment references.\n\n```js\nconst mongoose = require('mongoose');\nconst AutoIncrement = require('mongoose-sequence')(mongoose);\n```\n\nIf you use different connections you must include it this way\n\n```js\nconst mongoose = require('mongoose');\nconst AutoIncrementFactory = require('mongoose-sequence');\n\nconst connection = await mongoose.createConnection('mongodb://...');\n\nconst AutoIncrement = AutoIncrementFactory(connection);\n```\n\n## Global sequences\n\nLet's say you want to have an `id` field in your `user` collection which has a unique auto-incremented value.\n\nThe user schema is something like this:\n\n```js\nUserSchema = mongoose.Schema({\n  name: String,\n});\n\nmongoose.model('User', UserSchema);\n```\n\nYou don't need to define the `id` field in your schema because the plugin automatically sets it for you. The only thing\nyou have to do is to call:\n\n```js\nUserSchema.plugin(AutoIncrement, { inc_field: 'id' });\n```\n\nafter requiring the plugin.\n\nEvery time a new user is created, the `id` field will have an incremented number. The operation is atomic and is based\non [this](https://docs.mongodb.com/v3.0/tutorial/create-an-auto-incrementing-field/) specification.\nA commodity collection named `counters` is created for you. You can override the name of this collection but we will see\nthis later with the `options`.\n\nIf you want to increment the `_id` field which is special to mongoose, you have to explicitly specify it as a Number and\ntell mongoose to not interfere:\n\n```js\nUserSchema = mongoose.Schema(\n  {\n    _id: Number,\n    name: String,\n  },\n  { _id: false },\n);\nUserSchema.plugin(AutoIncrement);\n```\n\nIn this case you don't have to specify `inc_field` because the default value is `_id`\n\n## Not automatic sequences\n\nLet's say our user model has a `rank` field which gives the rank of the user in a tournament. So it saves the arrival\norder of a user to the end of our amazing game. This field is of course a sequence but has to be incremented every time\nan event occurs. Because we have concurrent access to our database we want to be sure that the increment of this counter\nhappens safely.\nLet's start by modifying our schema:\n\n```js\nUserSchema = mongoose.Schema({\n  name: String,\n  rank: Number,\n});\n```\n\nThis time we specified explicitly the field `rank`. There is no difference between defining and omitting the field\nspecification. The only constraint is that the field has to be of type `Number`, otherwise the plugin will raise an\nerror.\nSo, let's tell the plugin we want the `rank` field to be a safe counter:\n\n```js\nUserSchema.plugin(AutoIncrement, { inc_field: 'rank', disable_hooks: true });\n```\n\nWe specified `disable_hooks`. This avoids the field being incremented when a new document is saved. So, how to increment\nthis field? Your models have a new method: **setNext**. You must specify which sequence you want to increment and a\ncallback. Here's an example:\n\n```js\nUser.findOne({ name: 'George' }, function (err, user) {\n  user.setNext('rank', function (err, user) {\n    if (err) console.log('Cannot increment the rank because ', err);\n  });\n});\n```\n\nYou noticed that the method `setNext` takes, as argument, the counter field name. It is possible to give a name to the\ncounter and use it as reference. For the previous example we can define the counter like this:\n\n```js\nUserSchema.plugin(AutoIncrement, {\n  id: 'rank_counter',\n  inc_field: 'rank',\n  disable_hooks: true,\n});\n```\n\nand then use:\n\n```js\nuser.setNext('rank_counter', function (err, user) {\n  //...\n});\n```\n\nSo, 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\nstrongly suggested. This is because if you have two different counters, which refers to fields with the same name, they\nwill collide and incrementing one will increment the other too. Counters are not bound to the schema they refer to, so\ntwo counters for two different schemas can collide.\nSo use a unique id to be sure to avoid collision. In the case of a collision the plugin will raise an error.\n\nAs we will see, the use of an id for the counter is mandatory when you're defining a `scoped counter`.\n\n**NOTE**: When you call `setNext` the document is automatically saved. This behavior has changed since version 3.0.0. If\nyou use a prior version you have to call save by yourself.\n\n## Advanced\n\n### Scoped counters\n\nLet's say our users are organized by `country` and `city` and we want to save the `inhabitant_number` according to these\ntwo pieces of information.  \nThe schema is like this:\n\n```js\nUserSchema = mongoose.Schema({\n  name: String,\n  country: String,\n  city: String,\n  inhabitant_number: Number,\n});\n```\n\nEvery time a new Parisian is added, the count of Parisians has to be incremented. The inhabitants of New York must not\ninterfere, and have their separate counting. We should define a **scoped** counter which increments the counter\ndepending on the value of other fields.\n\n```js\nUserSchema.plugin(AutoIncrement, {\n  id: 'inhabitant_seq',\n  inc_field: 'inhabitant_number',\n  reference_fields: ['country', 'city'],\n});\n```\n\nNotice that we have to use an id for our sequence, otherwise the plugin will raise an error.\nNow save a new user:\n\n```js\nvar user = new User({\n  name: 'Patrice',\n  country: 'France',\n  city: 'Paris',\n});\nuser.save();\n```\n\nThis user will have the `inhabitant_number` counter set to 1.\nIf now we add a new inhabitant from New York, this will have its counter set to 1 also, because the counter is referred\nto by the value of the fields `country` and `city`.\n\nIf we want to increment this counter manually we have to specify the id of the sequence in the `setNext` method:\n\n```js\nuser.setNext('inhabitant_seq', function (err, user) {\n  user.inhabitant_number; // the counter value\n});\n```\n\nOf course this example is a bit forced and this is for sure not the perfect use case. The fields `country` and `city`\nhave to be present and must not change during the life of the document because no automatic hooks are set on the change\nof those values. But there are situations when you want a similar behavior.\n\n### Reset a counter\n\nIt's possible to programmatically reset a counter through the Model's static\nmethod `counterReset(id, reference, callback)`. The method takes these parameters:\n\n- **id**: the counter to reset. It's mandatory\n- **reference**: Lets you reset only a specific reference of the counter, if the counter has referenced fields.\n  Optional. By default it resets all the counters for the `id`\n- **callback**: A callback which receives an error in case of any. Mandatory\n\nSome examples:\n\n```js\nModel.counterReset('counter_id', function (err) {\n  // Now the counter is 0\n});\n\nModel.counterReset('inhabitants_id', function (err) {\n  // If this is a referenced field, now all the counters are 0\n});\n\nModel.counterReset(\n  'inhabitants_id',\n  { country: 'France', city: 'Paris' },\n  function (err) {\n    // If this is a referenced field, only the counter for Paris/France is 0\n  },\n);\n```\n\n### Nested fields\n\nIt is possible to define a nested field as counter, using `.` as the path separator:\n\n```js\nNestedSchema = new mongoose.Schema({\n  name: { type: String },\n  registration: {\n    date: { type: Date },\n    number: { type: Number },\n  },\n});\n\nNestedSchema.plugin(AutoIncrement, {\n  id: 'user_registration_seq',\n  inc_field: 'registration.number',\n});\n```\n\n### Options\n\nThis plugin accepts the following options:\n\n- **inc_field**: The name of the field to increment. Mandatory, default is `_id`.\n- **id**: Id of the sequence. Mandatory only for scoped sequences but its use is strongly encouraged.\n- **reference_fields**: The field to reference for a scoped counter. Optional.\n- **start_seq**: The number to start the sequence from. Optional, default `1`.\n- **inc_amount**: The quantity to increase the counter at each increment. Optional, default `1`.\n- **disable_hooks**: If true, the counter will not be incremented on saving a new document. Default `false`.\n- **collection_name**: By default the collection name to mantain the status of the counters is `counters`. You can\n  override it using this option.\n- **parallel_hooks**: If true, hooks will be registered as parallel. Default `true`.\n\n## Notes\n\nWhen using `insertMany` the plugin won't increment the counter because the needed hooks are not called. If you need to\ncreate several documents at once, use `create` instead and pass an array of documents (refer\nto [#7](https://github.com/ramiel/mongoose-sequence/issues/7)).\n","funding_links":["https://github.com/sponsors/ramiel","https://www.paypal.me/FabrizioRuggeri"],"categories":["JavaScript","🎁 Miscellaneous"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Framiel%2Fmongoose-sequence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Framiel%2Fmongoose-sequence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Framiel%2Fmongoose-sequence/lists"}