{"id":14956925,"url":"https://github.com/codemeasandwich/mongoose-model-stream","last_synced_at":"2025-10-24T10:31:11.198Z","repository":{"id":57302153,"uuid":"71068857","full_name":"codemeasandwich/mongoose-model-stream","owner":"codemeasandwich","description":"a mongoose model generator with a change stream","archived":false,"fork":false,"pushed_at":"2022-04-11T09:03:15.000Z","size":36,"stargazers_count":3,"open_issues_count":8,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-29T04:05:12.299Z","etag":null,"topics":["changes-stream","mongodb","mongoose","server-to-server","stream","websocket"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codemeasandwich.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-16T18:25:32.000Z","updated_at":"2022-01-15T12:20:23.000Z","dependencies_parsed_at":"2022-09-20T16:41:10.061Z","dependency_job_id":null,"html_url":"https://github.com/codemeasandwich/mongoose-model-stream","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemeasandwich%2Fmongoose-model-stream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemeasandwich%2Fmongoose-model-stream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemeasandwich%2Fmongoose-model-stream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemeasandwich%2Fmongoose-model-stream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codemeasandwich","download_url":"https://codeload.github.com/codemeasandwich/mongoose-model-stream/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237950913,"owners_count":19392667,"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":["changes-stream","mongodb","mongoose","server-to-server","stream","websocket"],"created_at":"2024-09-24T13:13:44.796Z","updated_at":"2025-10-24T10:31:05.902Z","avatar_url":"https://github.com/codemeasandwich.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mongoose-model-stream\n\na mongoose model generator with a change stream\n\n**info:**\n\n[![npm version](https://badge.fury.io/js/mongoose-model-stream.svg)](https://www.npmjs.com/package/mongoose-model-stream)\n[![License](http://img.shields.io/:license-apache_2-yellow.svg)](https://www.apache.org/licenses/LICENSE-2.0)\n\n\n### If this was helpful, [★ it on github](https://github.com/codemeasandwich/mongoose-model-stream)\n\n# Install\n\n`yarn add mongoose-model-stream`\n\n**or**\n\n`npm install --save mongoose-model-stream`\n\n# How to Use\n\n``` js\nconst moduleStream = require('mongoose-model-stream');\n```\n\n### constructor\n\nThis `moduleStream` function takes two arguments.\n\n* `modelName`: The name of the model\n* `schema` : The schema definition of the model.\n\nThere is also an optional 3rd argument.\n\n* `options` OR `enableDownStream`\n    * options: the options **object** that will be passed to the change stream schema. You can set `enableDownStream` as a Property on options\n    * enableDownStream: A **boolean** to change will create change events, without listening to the stream for updates. *(Default: `true`)*\n\n``` js\nconst ChatSchema = new mongoose.schema({\n  text: String\n});\n\nconst Chat = moduleStream('Chat', ChatSchema);\n```\n\nAttached to `Chat` will be a `.stream` baced on [RxJs]. This will **emit** change events baced on [rfc6902]\n\nThe payload looks like:\n\n| Property | Type |Description\n|--- |--- |---\n| patchs | Array | Present for all changes to the item. - An array of [rfc6902] operations.\n| target | String(ID) | The Unique identifier for the target Object\n| _id | String(ID)| The Unique identifier for this diff\n| createdAt | String(Date) | The time the chage was made\n| tag | String | A customisable identifier for this change\n| action | String(Enum) | This will be \"**CREATE**\", \"**UPDATE**\" or \"**DELETE**\" depending on the state of the document in the database\n| getChange | fn() ➜ Obj |  an object with only the changes applied\n| getTarget | fn() ➜ promise ➜ doc |  get the target document from the Database\n\n### model\n\n#### Create\n\nA new function will be added to the model\n\n* `saveBy` : This is used the tag a change with who made it.\n\n``` js\nevent.when = \"today\";\nevent.saveBy(user);\n```\n\nA `saveBy` **id** will be add to the change record\n\n**Outputted change**\n``` js\n{ patchs:\n   [ {\n     op: 'add',\n     path: '/when',\n     value: 'today'\n   } ],\n  _id: '5a958d12fc413a44ac760fb1',\n  target: '5a958d11fc413a44ac760fa9',\n  saveBy: '5a95872c39c0be3afaeb9a86',\n  createdAt: '2018-08-12T04:46:02.009Z',\n  action: \"UPDATE\"\n}\n```\n\n#### Update\n\n* **\"saveBy\"** is also provided in the `update` function(s)\n   * `update`, `updateMany`, `updateOne`, `findOneAndUpdate`, `findByIdAndUpdate`\n \nYou said the  **\"saveBy\"** bypassing it in the *\"options\"* argument.\nThis can be an **ID of an object(String)** that will be used for all patchs \nor a **function** to calculate the ID for each specific updated document\n\n```js\nconst conditions = {foo:true },\nupdateValues = {setBarTo:false},\noptions = {savedBy:(oldDoc,newDoc,patchs)=\u003eoldDoc.user_id}\nevent.updateMany(conditions,update,options)\n```\n\n### tag\n\nA custom string denoting the change can be added to the following functions\n\n * Create\n e.g. `` const event = await Module.create({ text:updateTextTag },{ tag :\"FOO_1\" })``\n * save\n e.g. ``event.save(\"FOO_2\")``  or ``event.save({ tag :\"FOO_3\"})`` \n * saveBy\n e.g. ``event.saveBy(user,\"FOO_4\")``\n * update\n e.g. ``Module.updateOne({_id},{$set:{text:\"bar\"}},{ tag : \"FOO_5\" })``\n\n----\n\n# run samples\n\n``` bash\nnode example/sample.js\n```\n\n# Example\n\n``` js\nrequire('mongoose-model-stream');\nconst { Schema, moduleStream } = require('mongoose');\n\n// create a schema\nconst ChatSchema = new Schema({ text: String }, { timestamps: true });\n\n// create a module\nconst Chat = moduleStream('Chat', ChatSchema);\n\n// subscribe to change events\nChat.stream.subscribe(console.log, console.error, console.info);\n\nChat.create({ text: \"foo\" })\n    .then(function (chatMessage) {\n        chatMessage.text = \"bar\";\n return chatMessage.save();\n    }).then(function (chatMessage) {\n        chatMessage.text = \"baz\";\n        chatMessage.save();\n    }).catch(console.error);\n```\n\n### Output:\n\n**Change: 1**\n``` js\n{ patchs:\n   [ {\n     op: 'add',\n     path: '/text',\n     value: :'foo'\n   }, {\n     op: 'add',\n     path: '/_id',\n     value: '5a86eea992f78d54f1cd65e9'\n   }, {\n     op: 'add',\n     path: '/updatedAt',\n     value: :'2018-08-12T04:46:01.993Z'\n   }, {\n     op: 'add',\n     path: '/createdAt',\n     value: '2018-08-12T04:46:01.993Z'\n   }  ],\n  _id: '5a86eeaa92f78d54f1cd65ea',\n  target: '5a86eea992f78d54f1cd65e9',\n  createdAt: '2018-08-12T04:46:02.009Z',\n  action: \"CREATE\"\n}\n```\n\n**Change: 2**\n``` js\n{ patchs:\n   [ { op: 'test', path: '/updatedAt', value: '2018-08-12T04:46:01.993Z' },\n     { op: 'replace', path: '/text', value: 'bar' },\n     { op: 'replace', path: '/updatedAt', value: '2018-08-12T04:46:02.116Z' }, ],\n  _id: '5a86eeaa92f78d54f1cd65eb',\n  target: '5a86eea992f78d54f1cd65e9',\n  createdAt: '2018-08-12T04:46:02.022Z',\n  action: \"UPDATE\"\n }\n```\n\n**Change: 3**\n``` js\n{ patchs:\n   [ { op: 'test', path: '/updatedAt', value: '2018-08-12T04:46:02.116Z' },\n     { op: 'replace', path: '/text', value: 'baz' },\n     { op: 'replace', path: '/updatedAt', value: '2018-08-12T04:46:02.342Z' }, ],\n  _id: '5a86eeaa92f78d54f1cd65ec',\n  target: '5a86eea992f78d54f1cd65e9',\n  createdAt: '2018-08-12T04:46:02.122Z',\n  action: \"UPDATE\"\n }\n```\n[RxJs]: http://reactivex.io/rxjs/\n[rfc6902]: https://tools.ietf.org/html/rfc6902\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodemeasandwich%2Fmongoose-model-stream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodemeasandwich%2Fmongoose-model-stream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodemeasandwich%2Fmongoose-model-stream/lists"}