├── .editorconfig ├── .github ├── contributing.md ├── issue_template.md ├── pull_request_template.md └── workflows │ ├── nodejs.yml │ └── update-dependencies.yml ├── .gitignore ├── .nycrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib ├── error-handler.js └── index.js ├── package-lock.json ├── package.json ├── test └── index.test.js └── types ├── index.d.ts ├── index.test.ts ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Feathers 2 | 3 | Thank you for contributing to Feathers! :heart: :tada: 4 | 5 | This repo is the main core and where most issues are reported. Feathers embraces modularity and is broken up across many repos. To make this easier to manage we currently use [Zenhub](https://www.zenhub.com/) for issue triage and visibility. They have a free browser plugin you can install so that you can see what is in flight at any time, but of course you also always see current issues in Github. 6 | 7 | ## Report a bug 8 | 9 | Before creating an issue please make sure you have checked out the docs, specifically the [FAQ](https://docs.feathersjs.com/help/faq.html) section. You might want to also try searching Github. It's pretty likely someone has already asked a similar question. 10 | 11 | If you haven't found your answer please feel free to join our [slack channel](http://slack.feathersjs.com), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathers` or `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Slack and Github. 12 | 13 | Issues can be reported in the [issue tracker](https://github.com/feathersjs/feathers/issues). Since feathers combines many modules it can be hard for us to assess the root cause without knowing which modules are being used and what your configuration looks like, so **it helps us immensely if you can link to a simple example that reproduces your issue**. 14 | 15 | ## Report a Security Concern 16 | 17 | We take security very seriously at Feathers. We welcome any peer review of our 100% open source code to ensure nobody's Feathers app is ever compromised or hacked. As a web application developer you are responsible for any security breaches. We do our very best to make sure Feathers is as secure as possible by default. 18 | 19 | In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Slack](http://slack.feathersjs.com) or email us at hello@feathersjs.com with details and we will respond ASAP. 20 | 21 | For full details refer to our [Security docs](https://docs.feathersjs.com/SECURITY.html). 22 | 23 | ## Pull Requests 24 | 25 | We :heart: pull requests and we're continually working to make it as easy as possible for people to contribute, including a [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) and a [common test suite](https://github.com/feathersjs/feathers-service-tests) for database adapters. 26 | 27 | We prefer small pull requests with minimal code changes. The smaller they are the easier they are to review and merge. A core team member will pick up your PR and review it as soon as they can. They may ask for changes or reject your pull request. This is not a reflection of you as an engineer or a person. Please accept feedback graciously as we will also try to be sensitive when providing it. 28 | 29 | Although we generally accept many PRs they can be rejected for many reasons. We will be as transparent as possible but it may simply be that you do not have the same context or information regarding the roadmap that the core team members have. We value the time you take to put together any contributions so we pledge to always be respectful of that time and will try to be as open as possible so that you don't waste it. :smile: 30 | 31 | **All PRs (except documentation) should be accompanied with tests and pass the linting rules.** 32 | 33 | ### Code style 34 | 35 | Before running the tests from the `test/` folder `npm test` will run ESlint. You can check your code changes individually by running `npm run lint`. 36 | 37 | ### ES6 compilation 38 | 39 | Feathers uses [Babel](https://babeljs.io/) to leverage the latest developments of the JavaScript language. All code and samples are currently written in ES2015. To transpile the code in this repository run 40 | 41 | > npm run compile 42 | 43 | __Note:__ `npm test` will run the compilation automatically before the tests. 44 | 45 | ### Tests 46 | 47 | [Mocha](http://mochajs.org/) tests are located in the `test/` folder and can be run using the `npm run mocha` or `npm test` (with ESLint and code coverage) command. 48 | 49 | ### Documentation 50 | 51 | Feathers documentation is contained in Markdown files in the [feathers-docs](https://github.com/feathersjs/feathers-docs) repository. To change the documentation submit a pull request to that repo, referencing any other PR if applicable, and the docs will be updated with the next release. 52 | 53 | ## External Modules 54 | 55 | If you're written something awesome for Feathers, the Feathers ecosystem, or using Feathers please add it to the [showcase](https://docs.feathersjs.com/why/showcase.html). You also might want to check out the [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) that can be used to scaffold plugins to be Feathers compliant from the start. 56 | 57 | If you think it would be a good core module then please contact one of the Feathers core team members in [Slack](http://slack.feathersjs.com) and we can discuss whether it belongs in core and how to get it there. :beers: 58 | 59 | ## Contributor Code of Conduct 60 | 61 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 62 | 63 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 64 | 65 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 66 | 67 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 68 | 69 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 72 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Steps to reproduce 2 | 3 | (First please check that this issue is not already solved as [described 4 | here](https://github.com/feathersjs/feathers/blob/master/.github/contributing.md#report-a-bug)) 5 | 6 | - [ ] Tell us what broke. The more detailed the better. 7 | - [ ] If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc. 8 | 9 | ### Expected behavior 10 | Tell us what should happen 11 | 12 | ### Actual behavior 13 | Tell us what happens instead 14 | 15 | ### System configuration 16 | 17 | Tell us about the applicable parts of your setup. 18 | 19 | **Module versions** (especially the part that's not working): 20 | 21 | **NodeJS version**: 22 | 23 | **Operating System**: 24 | 25 | **Browser Version**: 26 | 27 | **React Native Version**: 28 | 29 | **Module Loader**: -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Summary 2 | 3 | (If you have not already please refer to the contributing guideline as [described 4 | here](https://github.com/feathersjs/feathers/blob/master/.github/contributing.md#pull-requests)) 5 | 6 | - [ ] Tell us about the problem your pull request is solving. 7 | - [ ] Are there any open issues that are related to this? 8 | - [ ] Is this PR dependent on PRs in other repos? 9 | 10 | If so, please mention them to keep the conversations linked together. 11 | 12 | ### Other Information 13 | 14 | If there's anything else that's important and relevant to your pull 15 | request, mention that information here. This could include 16 | benchmarks, or other information. 17 | 18 | Your PR will be reviewed by a core team member and they will work with you to get your changes merged in a timely manner. If merged your PR will automatically be added to the changelog in the next release. 19 | 20 | If your changes involve documentation updates please mention that and link the appropriate PR in [feathers-docs](https://github.com/feathersjs/feathers-docs). 21 | 22 | Thanks for contributing to Feathers! :heart: -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [12.x, 16.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Start MongoDB 17 | uses: supercharge/mongodb-github-action@1.6.0 18 | with: 19 | mongodb-version: 4.4 20 | mongodb-replica-set: test-rs 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v1 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | - run: npm install 26 | - run: npm test 27 | env: 28 | CI: true 29 | -------------------------------------------------------------------------------- /.github/workflows/update-dependencies.yml: -------------------------------------------------------------------------------- 1 | name: Update dependencies 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 1 * *' 6 | workflow_dispatch: 7 | jobs: 8 | update-dependencies: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Use Node.js 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: '15.x' 16 | - run: npm ci 17 | - run: | 18 | git config user.name "GitHub Actions Bot" 19 | git config user.email "hello@feathersjs.com" 20 | git checkout -b update-dependencies-$GITHUB_RUN_ID 21 | - run: | 22 | npm run update-dependencies 23 | npm install 24 | - run: | 25 | git commit -am "chore(dependencies): Update dependencies" 26 | git push origin update-dependencies-$GITHUB_RUN_ID 27 | - run: | 28 | gh pr create --title "chore(dependencies): Update all dependencies" --body "" 29 | env: 30 | GITHUB_TOKEN: ${{secrets.CI_ACCESS_TOKEN}} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Logs 4 | logs 5 | *.log 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | .nyc_output 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # Commenting this out is preferred by some people, see 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 28 | node_modules 29 | 30 | # Users Environment Variables 31 | .lock-wscript 32 | 33 | data/ 34 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "verbose": false, 3 | "tempDirectory": "./coverage/.tmp", 4 | "semistandard": { 5 | "env": [ 6 | "mocha" 7 | ] 8 | }, 9 | "extension": [ 10 | ".ts", 11 | ".tsx", 12 | ".js" 13 | ], 14 | "exclude": [ 15 | "**/test/*" 16 | ], 17 | "print": "detail", 18 | "reporter": [ 19 | "html", 20 | "text", 21 | "text-summary", 22 | "lcov" 23 | ], 24 | "watermarks": { 25 | "statements": [ 26 | 70, 27 | 90 28 | ], 29 | "lines": [ 30 | 70, 31 | 90 32 | ], 33 | "functions": [ 34 | 70, 35 | 90 36 | ], 37 | "branches": [ 38 | 70, 39 | 90 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/HEAD) 4 | 5 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.4.1...HEAD) 6 | 7 | **Merged pull requests:** 8 | 9 | - fix: add missing options on findOne in \_create [\#199](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/199) ([arlukin](https://github.com/arlukin)) 10 | 11 | ## [v6.4.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.4.1) (2021-10-06) 12 | 13 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.4.0...v6.4.1) 14 | 15 | ## [v6.4.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.4.0) (2021-09-29) 16 | 17 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.3.1...v6.4.0) 18 | 19 | **Closed issues:** 20 | 21 | - Compatibility with mongo driver V4 [\#197](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/197) 22 | - Error when upgrade package mongodb to 4.0.1 [\#194](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/194) 23 | 24 | **Merged pull requests:** 25 | 26 | - Add MongoDB 4 driver compatibility and upgrade dependencies and project infrastructure [\#198](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/198) ([daffl](https://github.com/daffl)) 27 | 28 | ## [v6.3.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.3.1) (2021-08-30) 29 | 30 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.3.0...v6.3.1) 31 | 32 | **Implemented enhancements:** 33 | 34 | - \[Feature request\] Support transactions [\#127](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/127) 35 | 36 | **Closed issues:** 37 | 38 | - Why this query is not using the index? \( keysExamined: 0 docsExamined: 27417057 \) [\#195](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/195) 39 | 40 | **Merged pull requests:** 41 | 42 | - Mongodb 4 compatibility [\#196](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/196) ([Noobulater](https://github.com/Noobulater)) 43 | - Fix typo in README [\#192](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/192) ([ericirish](https://github.com/ericirish)) 44 | 45 | ## [v6.3.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.3.0) (2020-11-24) 46 | 47 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.2.0...v6.3.0) 48 | 49 | **Closed issues:** 50 | 51 | - Regex not working [\#190](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/190) 52 | 53 | **Merged pull requests:** 54 | 55 | - Add support for passing `options` \(or `mongodb`\) to all methods. [\#189](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/189) ([rudolph9](https://github.com/rudolph9)) 56 | 57 | ## [v6.2.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.2.0) (2020-09-27) 58 | 59 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.1.0...v6.2.0) 60 | 61 | **Closed issues:** 62 | 63 | - $geoNear, $near, and $nearSphere are not allowed in this context [\#185](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/185) 64 | - Support for bulkWrite [\#183](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/183) 65 | - An in-range update of @types/mongodb is breaking the build 🚨 [\#177](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/177) 66 | - An in-range update of dtslint is breaking the build 🚨 [\#173](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/173) 67 | - An in-range update of @feathersjs/adapter-commons is breaking the build 🚨 [\#172](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/172) 68 | 69 | **Merged pull requests:** 70 | 71 | - Properly return items on patch methods [\#188](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/188) ([DaddyWarbucks](https://github.com/DaddyWarbucks)) 72 | - feat: Added useEstimatedDocumentCount option [\#186](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/186) ([claustres](https://github.com/claustres)) 73 | - Update all dependencies [\#180](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/180) ([daffl](https://github.com/daffl)) 74 | - chore\(package\): update @types/mongodb to version 3.5.3 [\#179](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/179) ([daffl](https://github.com/daffl)) 75 | - Update dtslint to the latest version 🚀 [\#176](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/176) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 76 | - chore\(package\): update mongodb to version 3.5.3 [\#175](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/175) ([daffl](https://github.com/daffl)) 77 | - Update all dependencies and Types version [\#174](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/174) ([daffl](https://github.com/daffl)) 78 | 79 | ## [v6.1.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.1.0) (2019-11-21) 80 | 81 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v6.0.0...v6.1.0) 82 | 83 | **Closed issues:** 84 | 85 | - RegExp in $in inside query does not get passed to server properly. [\#170](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/170) 86 | - An in-range update of @feathersjs/adapter-commons is breaking the build 🚨 [\#163](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/163) 87 | 88 | **Merged pull requests:** 89 | 90 | - Add disableObjectify option to use normal strings as id [\#171](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/171) ([ydeshayes](https://github.com/ydeshayes)) 91 | - Update dtslint to the latest version 🚀 [\#168](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/168) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 92 | - Update dtslint to version 1.0.2 [\#166](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/166) ([daffl](https://github.com/daffl)) 93 | - Greenkeeper/@feathersjs/adapter commons 4.3.8 [\#164](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/164) ([daffl](https://github.com/daffl)) 94 | 95 | ## [v6.0.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v6.0.0) (2019-10-07) 96 | 97 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v5.0.1...v6.0.0) 98 | 99 | **Fixed bugs:** 100 | 101 | - find with string \_id randomly stops working [\#151](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/151) 102 | 103 | **Merged pull requests:** 104 | 105 | - Update all dependencies [\#162](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/162) ([daffl](https://github.com/daffl)) 106 | - Remove automated ObjectID conversion [\#161](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/161) ([daffl](https://github.com/daffl)) 107 | 108 | ## [v5.0.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v5.0.1) (2019-09-29) 109 | 110 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v5.0.0...v5.0.1) 111 | 112 | **Closed issues:** 113 | 114 | - how to wait for all models to be ready? [\#158](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/158) 115 | - An in-range update of run-rs is breaking the build 🚨 [\#155](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/155) 116 | - An in-range update of @types/mongodb is breaking the build 🚨 [\#147](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/147) 117 | - Update data using custom identifier [\#146](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/146) 118 | 119 | **Merged pull requests:** 120 | 121 | - Pass entity type to AdapterService\ and update dependencies [\#160](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/160) ([daffl](https://github.com/daffl)) 122 | - Update run-rs to the latest version 🚀 [\#159](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/159) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 123 | - Greenkeeper/run rs 0.5.5 [\#157](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/157) ([daffl](https://github.com/daffl)) 124 | - Greenkeeper/mongodb 3.3.1 [\#153](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/153) ([daffl](https://github.com/daffl)) 125 | - Update semistandard to the latest version 🚀 [\#149](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/149) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 126 | - Greenkeeper/mongodb 3.3.0 [\#148](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/148) ([daffl](https://github.com/daffl)) 127 | - Update dtslint to the latest version 🚀 [\#145](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/145) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 128 | 129 | ## [v5.0.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v5.0.0) (2019-07-06) 130 | 131 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v4.0.4...v5.0.0) 132 | 133 | **Closed issues:** 134 | 135 | - An in-range update of mongodb is breaking the build 🚨 [\#142](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/142) 136 | - BadRequest: Invalid query parameter $geoWithin [\#141](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/141) 137 | - An in-range update of mocha is breaking the build 🚨 [\#139](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/139) 138 | 139 | **Merged pull requests:** 140 | 141 | - Add TypeScript definitions and upgrade tests to Feathers 4 [\#144](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/144) ([daffl](https://github.com/daffl)) 142 | - Update all dependencies and compatible Node version [\#143](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/143) ([daffl](https://github.com/daffl)) 143 | - Update run-rs to the latest version 🚀 [\#140](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/140) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 144 | - Update mocha to the latest version 🚀 [\#138](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/138) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 145 | 146 | ## [v4.0.4](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v4.0.4) (2019-01-12) 147 | 148 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v4.0.3...v4.0.4) 149 | 150 | ## [v4.0.3](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v4.0.3) (2019-01-12) 151 | 152 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v4.0.2...v4.0.3) 153 | 154 | **Merged pull requests:** 155 | 156 | - Make sure ids in queries are respected [\#137](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/137) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 157 | 158 | ## [v4.0.2](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v4.0.2) (2019-01-03) 159 | 160 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v4.0.1...v4.0.2) 161 | 162 | **Closed issues:** 163 | 164 | - An in-range update of @feathersjs/adapter-commons is breaking the build 🚨 [\#135](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/135) 165 | - An in-range update of @feathersjs/errors is breaking the build 🚨 [\#134](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/134) 166 | 167 | **Merged pull requests:** 168 | 169 | - Add a Model setter [\#136](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/136) ([daffl](https://github.com/daffl)) 170 | 171 | ## [v4.0.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v4.0.1) (2018-12-29) 172 | 173 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v4.0.0...v4.0.1) 174 | 175 | **Closed issues:** 176 | 177 | - An in-range update of @feathersjs/adapter-commons is breaking the build 🚨 [\#132](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/132) 178 | 179 | **Merged pull requests:** 180 | 181 | - Add default params to hook-less service methods [\#133](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/133) ([daffl](https://github.com/daffl)) 182 | 183 | ## [v4.0.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v4.0.0) (2018-12-17) 184 | 185 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v3.4.0...v4.0.0) 186 | 187 | **Implemented enhancements:** 188 | 189 | - \[Feature request\] increase performances using bulk write [\#123](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/123) 190 | 191 | **Fixed bugs:** 192 | 193 | - Update method shows deprecation warning [\#122](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/122) 194 | 195 | **Closed issues:** 196 | 197 | - Still seeing the deprecation messages even after updating to 3.4.0 [\#128](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/128) 198 | 199 | **Merged pull requests:** 200 | 201 | - Upgrade to @feathersjs/adapter-commons and latest common service features [\#131](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/131) ([daffl](https://github.com/daffl)) 202 | - Use run-rs to install local MongoDB [\#130](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/130) ([daffl](https://github.com/daffl)) 203 | - Add hint support [\#129](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/129) ([EliSadaka](https://github.com/EliSadaka)) 204 | 205 | ## [v3.4.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v3.4.0) (2018-11-15) 206 | 207 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v3.3.0...v3.4.0) 208 | 209 | **Implemented enhancements:** 210 | 211 | - \[enhancement\] use `findOneAndUpdate`, `findOneAndDelete` to speed up `patch`, `update` and `remove` [\#104](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/104) 212 | 213 | **Merged pull requests:** 214 | 215 | - Fix Deprecation warning issue \#122 with create, update, patch [\#126](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/126) ([Gerigot](https://github.com/Gerigot)) 216 | - Update semistandard to the latest version 🚀 [\#125](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/125) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 217 | 218 | ## [v3.3.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v3.3.0) (2018-08-05) 219 | 220 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v3.2.0...v3.3.0) 221 | 222 | **Merged pull requests:** 223 | 224 | - Update all dependencies [\#121](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/121) ([daffl](https://github.com/daffl)) 225 | - using countDocuments\(\) instead of count\(\) [\#119](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/119) ([v1p](https://github.com/v1p)) 226 | 227 | ## [v3.2.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v3.2.0) (2018-06-03) 228 | 229 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v3.1.0...v3.2.0) 230 | 231 | **Closed issues:** 232 | 233 | - export data to csv file [\#117](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/117) 234 | - $addToSet not working [\#116](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/116) 235 | 236 | **Merged pull requests:** 237 | 238 | - Update uberproto to the latest version 🚀 [\#118](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/118) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 239 | 240 | ## [v3.1.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v3.1.0) (2018-05-01) 241 | 242 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v3.0.1...v3.1.0) 243 | 244 | **Closed issues:** 245 | 246 | - Perfom an aggregation pipline [\#114](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/114) 247 | - field constraint [\#113](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/113) 248 | 249 | **Merged pull requests:** 250 | 251 | - Allow $modifiers to be used in patch [\#115](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/115) ([VincentExpoTech](https://github.com/VincentExpoTech)) 252 | 253 | ## [v3.0.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v3.0.1) (2018-02-04) 254 | 255 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v3.0.0...v3.0.1) 256 | 257 | **Closed issues:** 258 | 259 | - $select query field doesn't work in find\(\) method [\#110](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/110) 260 | - How save date type string as ISODate type field? [\#108](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/108) 261 | - Query $in doesn't works with \_id [\#106](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/106) 262 | - Gettting Page not found, Initial connect to db do not work? [\#105](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/105) 263 | - npm install download incompatible MongoClient version [\#102](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/102) 264 | 265 | **Merged pull requests:** 266 | 267 | - Update $select query [\#111](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/111) ([jansel369](https://github.com/jansel369)) 268 | - Update mocha to the latest version 🚀 [\#109](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/109) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 269 | - Update semistandard to the latest version 🚀 [\#107](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/107) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 270 | - Upgrade to mongo driver 3.0.0-rc0 [\#103](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/103) ([davidnussio](https://github.com/davidnussio)) 271 | 272 | ## [v3.0.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v3.0.0) (2017-12-03) 273 | 274 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.9.1...v3.0.0) 275 | 276 | **Merged pull requests:** 277 | 278 | - Update to Feathers Buzzard \(v3\) [\#100](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/100) ([daffl](https://github.com/daffl)) 279 | - Update to new plugin infrastructure [\#99](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/99) ([daffl](https://github.com/daffl)) 280 | 281 | ## [v2.9.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.9.1) (2017-10-19) 282 | 283 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.9.0...v2.9.1) 284 | 285 | **Closed issues:** 286 | 287 | - An in-range update of feathers-errors is breaking the build 🚨 [\#95](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/95) 288 | - An in-range update of feathers is breaking the build 🚨 [\#94](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/94) 289 | - Can't set properties on custom adapter extended from feathers-mongodb [\#93](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/93) 290 | - \_objectifyId / ObjectID.isValid converts legit string IDs to Mongo ObjectId [\#92](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/92) 291 | - the latest npm package is not updated? [\#89](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/89) 292 | 293 | **Merged pull requests:** 294 | 295 | - Coerce stringified ObjectIDs in find if present [\#98](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/98) ([adamvr](https://github.com/adamvr)) 296 | - Update mocha to the latest version 🚀 [\#97](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/97) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 297 | - Remove MongoDB service to force apt addon [\#96](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/96) ([daffl](https://github.com/daffl)) 298 | - Update chai to the latest version 🚀 [\#91](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/91) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 299 | - Update feathers-socketio to the latest version 🚀 [\#90](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/90) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 300 | 301 | ## [v2.9.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.9.0) (2017-05-09) 302 | 303 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.8.0...v2.9.0) 304 | 305 | **Closed issues:** 306 | 307 | - An in-range update of mongodb is breaking the build 🚨 [\#85](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/85) 308 | 309 | **Merged pull requests:** 310 | 311 | - Update feathers-service-tests to the latest version 🚀 [\#88](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/88) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 312 | - Update semistandard to the latest version 🚀 [\#86](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/86) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 313 | - Update feathers-hooks to the latest version 🚀 [\#84](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/84) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 314 | - Update dependencies to enable Greenkeeper 🌴 [\#83](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/83) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) 315 | 316 | ## [v2.8.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.8.0) (2017-01-19) 317 | 318 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.7.0...v2.8.0) 319 | 320 | **Merged pull requests:** 321 | 322 | - Allow setting the model later [\#82](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/82) ([daffl](https://github.com/daffl)) 323 | 324 | ## [v2.7.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.7.0) (2017-01-07) 325 | 326 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.6.0...v2.7.0) 327 | 328 | **Merged pull requests:** 329 | 330 | - mongodb@2.2.19 breaks build 🚨 [\#81](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/81) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 331 | - Add support for MongoDB collation. [\#79](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/79) ([JoshuaToenyes](https://github.com/JoshuaToenyes)) 332 | 333 | ## [v2.6.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.6.0) (2016-11-12) 334 | 335 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.5.1...v2.6.0) 336 | 337 | **Closed issues:** 338 | 339 | - How to unset a property of document [\#72](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/72) 340 | 341 | **Merged pull requests:** 342 | 343 | - Update feathers-service-tests to version 0.9.0 🚀 [\#78](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/78) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 344 | - babel-core@6.18.1 breaks build 🚨 [\#76](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/76) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 345 | - babel-preset-es2015@6.18.0 breaks build 🚨 [\#75](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/75) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 346 | - jshint —\> semistandard [\#71](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/71) ([marshallswain](https://github.com/marshallswain)) 347 | - adding code coverage reporting [\#69](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/69) ([ekryski](https://github.com/ekryski)) 348 | 349 | ## [v2.5.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.5.1) (2016-09-21) 350 | 351 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.5.0...v2.5.1) 352 | 353 | **Closed issues:** 354 | 355 | - Unique index on idField? [\#46](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/46) 356 | 357 | **Merged pull requests:** 358 | 359 | - Properly assign generated id when creating multiple [\#64](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/64) ([daffl](https://github.com/daffl)) 360 | - Properly patch multiple [\#63](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/63) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 361 | 362 | ## [v2.5.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.5.0) (2016-09-08) 363 | 364 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.4.2...v2.5.0) 365 | 366 | **Closed issues:** 367 | 368 | - TypeError: errors.handler is not a function [\#57](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/57) 369 | 370 | **Merged pull requests:** 371 | 372 | - Update service tests, id and events option [\#62](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/62) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 373 | - Update example in README.md [\#60](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/60) ([kulakowka](https://github.com/kulakowka)) 374 | - Update mocha to version 3.0.0 🚀 [\#54](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/54) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 375 | 376 | ## [v2.4.2](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.4.2) (2016-07-21) 377 | 378 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.4.1...v2.4.2) 379 | 380 | **Merged pull requests:** 381 | 382 | - Update feathers-query-filters to version 2.0.0 🚀 [\#53](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/53) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 383 | 384 | ## [v2.4.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.4.1) (2016-07-09) 385 | 386 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.4.0...v2.4.1) 387 | 388 | **Merged pull requests:** 389 | 390 | - feathers-service-tests@0.6.2 breaks build 🚨 [\#51](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/51) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 391 | 392 | ## [v2.4.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.4.0) (2016-07-08) 393 | 394 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.3.0...v2.4.0) 395 | 396 | **Fixed bugs:** 397 | 398 | - We shouldn't remove properties from original objects [\#49](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/49) 399 | 400 | **Merged pull requests:** 401 | 402 | - feathers-service-tests@0.6.1 breaks build 🚨 [\#50](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/50) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 403 | 404 | ## [v2.3.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.3.0) (2016-06-17) 405 | 406 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.2.0...v2.3.0) 407 | 408 | **Closed issues:** 409 | 410 | - Support $search [\#33](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/33) 411 | 412 | **Merged pull requests:** 413 | 414 | - Update feathers-service-tests to version 0.6.0 🚀 [\#47](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/47) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 415 | - Update test app to use ES6 imports. [\#45](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/45) ([joshuajabbour](https://github.com/joshuajabbour)) 416 | - mocha@2.5.0 breaks build 🚨 [\#44](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/44) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 417 | - Remove unnecessary param from \_multiOptions [\#43](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/43) ([joshuajabbour](https://github.com/joshuajabbour)) 418 | 419 | ## [v2.2.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.2.0) (2016-05-07) 420 | 421 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.1.3...v2.2.0) 422 | 423 | **Closed issues:** 424 | 425 | - objectifyId only converting for \_id field [\#40](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/40) 426 | - make yo service use this package instead of mongoose [\#30](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/30) 427 | 428 | **Merged pull requests:** 429 | 430 | - Move utility functions to service instance [\#42](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/42) ([joshuajabbour](https://github.com/joshuajabbour)) 431 | - Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\#41](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/41) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 432 | - babel-polyfill@6.7.4 breaks build 🚨 [\#39](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/39) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 433 | - Move ID handling logic into separate method. [\#36](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/36) ([joshuajabbour](https://github.com/joshuajabbour)) 434 | - nsp@2.3.2 breaks build 🚨 [\#35](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/35) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot)) 435 | 436 | ## [v2.1.3](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.1.3) (2016-02-24) 437 | 438 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.1.2...v2.1.3) 439 | 440 | **Merged pull requests:** 441 | 442 | - bumping feathers-errors version [\#29](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/29) ([ekryski](https://github.com/ekryski)) 443 | 444 | ## [v2.1.2](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.1.2) (2016-02-23) 445 | 446 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.1.1...v2.1.2) 447 | 448 | **Merged pull requests:** 449 | 450 | - enforcing that you shouldn't be able to change ids [\#28](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/28) ([ekryski](https://github.com/ekryski)) 451 | 452 | ## [v2.1.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.1.1) (2016-02-23) 453 | 454 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v2.1.0...v2.1.1) 455 | 456 | **Closed issues:** 457 | 458 | - Update/patch \(PUT/PATCH\) strips "id" from saved object [\#25](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/25) 459 | - Isn't update, patch, and remove supposed to support query like behavior? [\#21](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/21) 460 | - Upgrade to mongo-native 2.1 [\#20](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/20) 461 | - Update to ES6 and the Feathers 2.0 [\#16](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/16) 462 | 463 | **Merged pull requests:** 464 | 465 | - building on @joshuajabbour's pr. Adding support for patch. Closes \#25 [\#27](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/27) ([ekryski](https://github.com/ekryski)) 466 | - Always set "id" field during PUT updates [\#26](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/26) ([joshuajabbour](https://github.com/joshuajabbour)) 467 | 468 | ## [v2.1.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v2.1.0) (2016-02-22) 469 | 470 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v1.1.1...v2.1.0) 471 | 472 | **Closed issues:** 473 | 474 | - how to insert? [\#23](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/23) 475 | - Replacing "\_id" isn't possible, despite docs [\#22](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/22) 476 | 477 | **Merged pull requests:** 478 | 479 | - ES6 [\#24](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/24) ([ekryski](https://github.com/ekryski)) 480 | - Adding nsp check [\#19](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/19) ([marshallswain](https://github.com/marshallswain)) 481 | - Migrate to latest feathers-errors [\#18](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/18) ([daffl](https://github.com/daffl)) 482 | 483 | ## [v1.1.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v1.1.1) (2016-01-21) 484 | 485 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v1.1.0...v1.1.1) 486 | 487 | **Closed issues:** 488 | 489 | - Migrate to feathers-errors \>= 1.1.x [\#17](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/17) 490 | 491 | ## [v1.1.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v1.1.0) (2015-11-08) 492 | 493 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v1.0.2...v1.1.0) 494 | 495 | **Closed issues:** 496 | 497 | - need help extending mongodb [\#14](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/14) 498 | 499 | **Merged pull requests:** 500 | 501 | - Migrating to shared service tests [\#15](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/15) ([daffl](https://github.com/daffl)) 502 | 503 | ## [v1.0.2](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v1.0.2) (2015-10-25) 504 | 505 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v1.0.1...v1.0.2) 506 | 507 | **Closed issues:** 508 | 509 | - Passing config parameter to mongoService not working [\#12](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/12) 510 | 511 | **Merged pull requests:** 512 | 513 | - Fix mongoService construction, now accept the options parameter [\#13](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/13) ([PaGury](https://github.com/PaGury)) 514 | 515 | ## [v1.0.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v1.0.1) (2015-10-12) 516 | 517 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v1.0.0...v1.0.1) 518 | 519 | ## [v1.0.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v1.0.0) (2015-07-28) 520 | 521 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v0.3.3...v1.0.0) 522 | 523 | **Closed issues:** 524 | 525 | - No Open Connections [\#8](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/8) 526 | 527 | **Merged pull requests:** 528 | 529 | - Plugin consistency [\#11](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/11) ([ekryski](https://github.com/ekryski)) 530 | 531 | ## [v0.3.3](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v0.3.3) (2015-05-12) 532 | 533 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v0.3.2...v0.3.3) 534 | 535 | ## [v0.3.2](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v0.3.2) (2015-04-29) 536 | 537 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/v0.3.1...v0.3.2) 538 | 539 | ## [v0.3.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/v0.3.1) (2015-04-29) 540 | 541 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/0.3.1...v0.3.1) 542 | 543 | ## [0.3.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/0.3.1) (2015-04-06) 544 | 545 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/0.3.0...0.3.1) 546 | 547 | **Merged pull requests:** 548 | 549 | - Allow services to share a common db connection. [\#9](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/9) ([marshallswain](https://github.com/marshallswain)) 550 | 551 | ## [0.3.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/0.3.0) (2014-06-23) 552 | 553 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/0.2.1...0.3.0) 554 | 555 | **Closed issues:** 556 | 557 | - Add better documentation [\#6](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/6) 558 | - Should support `patch` service method [\#5](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/5) 559 | - MongoDB query needs to be flattened [\#2](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/2) 560 | - MongoDB .update should merge data [\#1](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/1) 561 | 562 | **Merged pull requests:** 563 | 564 | - MongoDB service update [\#7](https://github.com/feathersjs-ecosystem/feathers-mongodb/pull/7) ([daffl](https://github.com/daffl)) 565 | 566 | ## [0.2.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/0.2.1) (2014-06-13) 567 | 568 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/0.2.0...0.2.1) 569 | 570 | **Closed issues:** 571 | 572 | - Use Yeoman generator to initialize this repository [\#4](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/4) 573 | - Need to return proper errors [\#3](https://github.com/feathersjs-ecosystem/feathers-mongodb/issues/3) 574 | 575 | ## [0.2.0](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/0.2.0) (2014-06-05) 576 | 577 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/0.1.1...0.2.0) 578 | 579 | ## [0.1.1](https://github.com/feathersjs-ecosystem/feathers-mongodb/tree/0.1.1) (2014-04-11) 580 | 581 | [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-mongodb/compare/5208b94fa94e39864a27503a31a0084b37e01070...0.1.1) 582 | 583 | 584 | 585 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 586 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 FeathersJS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > __Important:__ This module has been moved to `@feathersjs/mongodb` and is developed in [feathersjs/feathers](https://github.com/feathersjs/feathers) 2 | 3 | # feathers-mongodb 4 | 5 | [![CI](https://github.com/feathersjs-ecosystem/feathers-mongodb/workflows/CI/badge.svg)](https://github.com/feathersjs-ecosystem/feathers-mongodb/actions?query=workflow%3ACI) 6 | [![Dependency Status](https://img.shields.io/david/feathersjs-ecosystem/feathers-mongodb.svg?style=flat-square)](https://david-dm.org/feathersjs-ecosystem/feathers-mongodb) 7 | [![Download Status](https://img.shields.io/npm/dm/feathers-mongodb.svg?style=flat-square)](https://www.npmjs.com/package/feathers-mongodb) 8 | 9 | A [Feathers](https://feathersjs.com) database adapter for [MongoDB](https://www.mongodb.org/) using [official NodeJS driver for MongoDB](https://www.npmjs.com/package/mongodb). 10 | 11 | ```bash 12 | $ npm install --save mongodb feathers-mongodb 13 | ``` 14 | 15 | > __Important:__ `feathers-mongodb` implements the [Feathers Common database adapter API](https://docs.feathersjs.com/api/databases/common.html) and [querying syntax](https://docs.feathersjs.com/api/databases/querying.html). 16 | 17 | > This adapter also requires a [running MongoDB](https://docs.mongodb.com/getting-started/shell/#) database server. 18 | 19 | 20 | ## API 21 | 22 | ### `service(options)` 23 | 24 | Returns a new service instance initialized with the given options. `Model` has to be a MongoDB collection. 25 | 26 | ```js 27 | const MongoClient = require('mongodb').MongoClient; 28 | const service = require('feathers-mongodb'); 29 | 30 | MongoClient.connect('mongodb://localhost:27017/feathers').then(client => { 31 | app.use('/messages', service({ 32 | Model: client.db('feathers').collection('messages') 33 | })); 34 | app.use('/messages', service({ Model, id, events, paginate })); 35 | }); 36 | ``` 37 | 38 | __Options:__ 39 | 40 | - `Model` (**required**) - The MongoDB collection instance 41 | - `id` (*optional*, default: `'_id'`) - The name of the id field property. By design, MongoDB will always add an `_id` property. 42 | - `disableObjectify` (*optional*, default `false`) - This will disable the objectify of the id field if you want to use normal strings 43 | - `events` (*optional*) - A list of [custom service events](https://docs.feathersjs.com/api/events.html#custom-events) sent by this service 44 | - `paginate` (*optional*) - A [pagination object](https://docs.feathersjs.com/api/databases/common.html#pagination) containing a `default` and `max` page size 45 | - `whitelist` (*optional*) - A list of additional query parameters to allow (e..g `[ '$regex', '$geoNear' ]`) 46 | - `multi` (*optional*) - Allow `create` with arrays and `update` and `remove` with `id` `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`) 47 | - `useEstimatedDocumentCount` (*optional*, default `false`) - If `true` document counting will rely on `estimatedDocumentCount` instead of `countDocuments` 48 | 49 | ### params.mongodb 50 | 51 | When making a [service method](https://docs.feathersjs.com/api/services.html) call, `params` can contain an `mongodb` property (for example, `{upsert: true}`) which allows to modify the options used to run the MongoDB query. 52 | 53 | #### Transactions 54 | 55 | You can utilized a [MongoDB Transactions](https://docs.mongodb.com/manual/core/transactions/) by passing a `session` with the `params.mongodb`: 56 | 57 | ```js 58 | import { ObjectID } from 'mongodb' 59 | 60 | export default async app => { 61 | app.use('/fooBarService', { 62 | async create(data) { 63 | // assumes you have access to the mongoClient via your app state 64 | let session = app.mongoClient.startSession() 65 | try { 66 | await session.withTransaction(async () => { 67 | let fooID = new ObjectID() 68 | let barID = new ObjectID() 69 | app.service('fooService').create( 70 | { 71 | ...data, 72 | _id: fooID, 73 | bar: barID, 74 | }, 75 | { mongodb: { session } }, 76 | ) 77 | app.service('barService').create( 78 | { 79 | ...data, 80 | _id: barID 81 | foo: fooID 82 | }, 83 | { mongodb: { session } }, 84 | ) 85 | }) 86 | } finally { 87 | await session.endSession() 88 | } 89 | } 90 | }) 91 | } 92 | ``` 93 | 94 | ## Example 95 | 96 | Here is an example of a Feathers server with a `messages` endpoint that writes to the `feathers` database and the `messages` collection. 97 | 98 | ``` 99 | $ npm install @feathersjs/feathers @feathersjs/errors @feathersjs/express @feathersjs/socketio feathers-mongodb mongodb 100 | ``` 101 | 102 | In `app.js`: 103 | 104 | ```js 105 | const feathers = require('@feathersjs/feathers'); 106 | const express = require('@feathersjs/express'); 107 | const socketio = require('@feathersjs/socketio'); 108 | 109 | const MongoClient = require('mongodb').MongoClient; 110 | const service = require('feathers-mongodb'); 111 | 112 | // Create an Express compatible Feathers application instance. 113 | const app = express(feathers()); 114 | // Turn on JSON parser for REST services 115 | app.use(express.json()); 116 | // Turn on URL-encoded parser for REST services 117 | app.use(express.urlencoded({extended: true})); 118 | // Enable REST services 119 | app.configure(express.rest()); 120 | // Enable Socket.io 121 | app.configure(socketio()); 122 | 123 | // Connect to the db, create and register a Feathers service. 124 | app.use('/messages', service({ 125 | paginate: { 126 | default: 2, 127 | max: 4 128 | } 129 | })); 130 | 131 | // A basic error handler, just like Express 132 | app.use(express.errorHandler()); 133 | 134 | // Connect to your MongoDB instance(s) 135 | MongoClient.connect('mongodb://localhost:27017/feathers') 136 | .then(function(client){ 137 | // Set the model now that we are connected 138 | app.service('messages').Model = client.db('feathers').collection('messages'); 139 | 140 | // Now that we are connected, create a dummy Message 141 | app.service('messages').create({ 142 | text: 'Message created on server' 143 | }).then(message => console.log('Created message', message)); 144 | }).catch(error => console.error(error)); 145 | 146 | // Start the server. 147 | const port = 3030; 148 | 149 | app.listen(port, () => { 150 | console.log(`Feathers server listening on port ${port}`); 151 | }); 152 | ``` 153 | 154 | Run the example with `node app` and go to [localhost:3030/messages](http://localhost:3030/messages). 155 | 156 | 157 | ## Querying 158 | 159 | Additionally to the [common querying mechanism](https://docs.feathersjs.com/api/databases/querying.html) this adapter also supports [MongoDB's query syntax](https://docs.mongodb.com/v3.2/tutorial/query-documents/) and the `update` method also supports MongoDB [update operators](https://docs.mongodb.com/v3.2/reference/operator/update/). 160 | 161 | > **Important:** External query values through HTTP URLs may have to be converted to the same type stored in MongoDB in a before [hook](https://docs.feathersjs.com/api/hooks.html) otherwise no matches will be found. Websocket requests will maintain the correct format if it is supported by JSON (ObjectIDs and dates still have to be converted). 162 | 163 | For example, an `age` (which is a number) a hook like this can be used: 164 | 165 | ```js 166 | const ObjectID = require('mongodb').ObjectID; 167 | 168 | app.service('users').hooks({ 169 | before: { 170 | find(context) { 171 | const { query = {} } = context.params; 172 | 173 | if(query.age !== undefined) { 174 | query.age = parseInt(query.age, 10); 175 | } 176 | 177 | context.params.query = query; 178 | 179 | return Promise.resolve(context); 180 | } 181 | } 182 | }); 183 | ``` 184 | 185 | Which will allows queries like `/users?_id=507f1f77bcf86cd799439011&age=25`. 186 | 187 | ## Collation Support 188 | 189 | This adapter includes support for [collation and case insensitive indexes available in MongoDB v3.4](https://docs.mongodb.com/manual/release-notes/3.4/#collation-and-case-insensitive-indexes). Collation parameters may be passed using the special `collation` parameter to the `find()`, `remove()` and `patch()` methods. 190 | 191 | ### Example: Patch records with case-insensitive alphabetical ordering 192 | 193 | The example below would patch all student records with grades of `'c'` or `'C'` and above (a natural language ordering). Without collations this would not be as simple, since the comparison `{ $gt: 'c' }` would not include uppercase grades of `'C'` because the code point of `'C'` is less than that of `'c'`. 194 | 195 | ```js 196 | const patch = { shouldStudyMore: true }; 197 | const query = { grade: { $gte: 'c' } }; 198 | const collation = { locale: 'en', strength: 1 }; 199 | students.patch(null, patch, { query, collation }).then( ... ); 200 | ``` 201 | 202 | ### Example: Find records with a case-insensitive search 203 | 204 | Similar to the above example, this would find students with a grade of `'c'` or greater, in a case-insensitive manner. 205 | 206 | ```js 207 | const query = { grade: { $gte: 'c' } }; 208 | const collation = { locale: 'en', strength: 1 }; 209 | students.find({ query, collation }).then( ... ); 210 | ``` 211 | 212 | For more information on MongoDB's collation feature, visit the [collation reference page](https://docs.mongodb.com/manual/reference/collation/). 213 | 214 | ## License 215 | 216 | Copyright (c) 2019 217 | 218 | Licensed under the [MIT license](LICENSE). 219 | -------------------------------------------------------------------------------- /lib/error-handler.js: -------------------------------------------------------------------------------- 1 | const errors = require('@feathersjs/errors'); 2 | 3 | module.exports = function errorHandler (error) { 4 | // NOTE (EK): The list of error code is way too massive to map 5 | // them to a specific error object so we'll use a generic one. 6 | // See https://github.com/mongodb/mongo/blob/master/docs/errors.md 7 | 8 | if (error.name === 'MongoError') { 9 | throw new errors.GeneralError(error, { 10 | ok: error.ok, 11 | code: error.code 12 | }); 13 | } 14 | 15 | throw error; 16 | }; 17 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const ObjectID = require('mongodb').ObjectID || require('mongodb').ObjectId; 2 | const errors = require('@feathersjs/errors'); 3 | const { _ } = require('@feathersjs/commons'); 4 | const { AdapterService, select } = require('@feathersjs/adapter-commons'); 5 | 6 | const errorHandler = require('./error-handler'); 7 | 8 | // Create the service. 9 | class Service extends AdapterService { 10 | constructor (options) { 11 | if (!options) { 12 | throw new Error('MongoDB options have to be provided'); 13 | } 14 | 15 | super(Object.assign({ 16 | id: '_id' 17 | }, options)); 18 | } 19 | 20 | get Model () { 21 | return this.options.Model; 22 | } 23 | 24 | set Model (value) { 25 | this.options.Model = value; 26 | } 27 | 28 | _objectifyId (id) { 29 | if (this.options.disableObjectify) { 30 | return id; 31 | } 32 | 33 | if (this.id === '_id' && ObjectID.isValid(id)) { 34 | id = new ObjectID(id.toString()); 35 | } 36 | 37 | return id; 38 | } 39 | 40 | _multiOptions (id, params = {}) { 41 | const { query } = this.filterQuery(params); 42 | const options = Object.assign({ multi: true }, params.mongodb || params.options); 43 | 44 | if (id !== null) { 45 | options.multi = false; 46 | query.$and = (query.$and || []).concat({ [this.id]: this._objectifyId(id) }); 47 | } 48 | 49 | return { query, options }; 50 | } 51 | 52 | _options (params = {}) { 53 | const { filters, query, paginate } = this.filterQuery(params); 54 | const options = Object.assign({}, params.mongodb || params.options); 55 | return { filters, query, paginate, options }; 56 | } 57 | 58 | _getSelect (select) { 59 | if (Array.isArray(select)) { 60 | const result = {}; 61 | select.forEach(name => { 62 | result[name] = 1; 63 | }); 64 | return result; 65 | } 66 | 67 | return select; 68 | } 69 | 70 | _findOrGet (id, params = {}) { 71 | if (id === null) { 72 | return this._find(params); 73 | } 74 | 75 | return this._get(id, params); 76 | } 77 | 78 | _normalizeId (id, data) { 79 | if (this.id === '_id') { 80 | // Default Mongo IDs cannot be updated. The Mongo library handles 81 | // this automatically. 82 | return _.omit(data, this.id); 83 | } else if (id !== null) { 84 | // If not using the default Mongo _id field set the ID to its 85 | // previous value. This prevents orphaned documents. 86 | return Object.assign({}, data, { [this.id]: id }); 87 | } 88 | return data; 89 | } 90 | 91 | // Map stray records into $set 92 | _remapModifiers (data) { 93 | let set = {}; 94 | // Step through the rooot 95 | for (const key in data) { 96 | // Check for keys that aren't modifiers 97 | if (key.charAt(0) !== '$') { 98 | // Move them to set, and remove their record 99 | set[key] = data[key]; 100 | delete data[key]; 101 | } 102 | // If the '$set' modifier is used, add that to the temp variable 103 | if (key === '$set') { 104 | set = Object.assign(set, data[key]); 105 | delete data[key]; 106 | } 107 | } 108 | // If we have a $set, then attach to the data object 109 | if (Object.keys(set).length > 0) { 110 | data.$set = set; 111 | } 112 | return data; 113 | } 114 | 115 | _find (params = {}) { 116 | // Start with finding all, and limit when necessary. 117 | const { filters, query, paginate, options } = this._options(params); 118 | 119 | if (query[this.id]) { 120 | query[this.id] = this._objectifyId(query[this.id]); 121 | } 122 | 123 | const q = this.Model.find(query, options); 124 | 125 | if (filters.$select) { 126 | q.project(this._getSelect(filters.$select)); 127 | } 128 | 129 | if (filters.$sort) { 130 | q.sort(filters.$sort); 131 | } 132 | 133 | if (params.collation) { 134 | q.collation(params.collation); 135 | } 136 | 137 | if (params.hint) { 138 | q.hint(params.hint); 139 | } 140 | 141 | if (filters.$limit) { 142 | q.limit(filters.$limit); 143 | } 144 | 145 | if (filters.$skip) { 146 | q.skip(filters.$skip); 147 | } 148 | 149 | let runQuery = total => { 150 | return q.toArray().then(data => { 151 | return { 152 | total, 153 | limit: filters.$limit, 154 | skip: filters.$skip || 0, 155 | data 156 | }; 157 | }); 158 | }; 159 | 160 | if (filters.$limit === 0) { 161 | runQuery = total => { 162 | return Promise.resolve({ 163 | total, 164 | limit: filters.$limit, 165 | skip: filters.$skip || 0, 166 | data: [] 167 | }); 168 | }; 169 | } 170 | 171 | if (paginate && paginate.default) { 172 | if (this.options.useEstimatedDocumentCount && (typeof this.Model.estimatedDocumentCount === 'function')) { 173 | return this.Model.estimatedDocumentCount(query, options).then(runQuery); 174 | } else { 175 | return this.Model.countDocuments(query, options).then(runQuery); 176 | } 177 | } 178 | 179 | return runQuery().then(page => page.data); 180 | } 181 | 182 | _get (id, params = {}) { 183 | const { query, options } = this._options(params); 184 | 185 | query.$and = (query.$and || []).concat({ [this.id]: this._objectifyId(id) }); 186 | 187 | return this.Model.findOne(query, options).then(data => { 188 | if (!data) { 189 | throw new errors.NotFound(`No record found for id '${id}'`); 190 | } 191 | 192 | return data; 193 | }).then(select(params, this.id)).catch(errorHandler); 194 | } 195 | 196 | _create (data, params = {}) { 197 | const { options } = this._options(params); 198 | const setId = item => { 199 | const entry = Object.assign({}, item); 200 | 201 | // Generate a MongoId if we use a custom id 202 | if (this.id !== '_id' && typeof entry[this.id] === 'undefined') { 203 | entry[this.id] = new ObjectID().toHexString(); 204 | } 205 | 206 | return entry; 207 | }; 208 | 209 | const promise = Array.isArray(data) 210 | ? this.Model.insertMany(data.map(setId), options) 211 | : this.Model.insertOne(setId(data), options); 212 | 213 | return promise.then(result => { 214 | if (result.insertedId) { 215 | return this.Model.findOne({ _id: result.insertedId }, options); 216 | } 217 | 218 | if (result.insertedIds) { 219 | return Promise.all(Object.values(result.insertedIds).map(_id => this.Model.findOne({ _id }, options))); 220 | } 221 | 222 | return result.ops.length > 1 ? result.ops : result.ops[0]; 223 | }).then(select(params, this.id)).catch(errorHandler); 224 | } 225 | 226 | _patch (id, data, params = {}) { 227 | let { query, options } = this._multiOptions(id, params); 228 | 229 | if (params.collation) { 230 | query = Object.assign(query, { collation: params.collation }); 231 | } 232 | 233 | const remapModifier = this._remapModifiers(this._normalizeId(id, data)); 234 | 235 | const idParams = Object.assign({}, params, { 236 | paginate: false 237 | }); 238 | 239 | const ids = this._findOrGet(id, idParams) 240 | .then(result => { 241 | const items = Array.isArray(result) ? result : [result]; 242 | return items.map(item => item[this.id]); 243 | }); 244 | 245 | return ids.then(idList => { 246 | const findParams = Object.assign({}, params, { 247 | paginate: false, 248 | query: { [this.id]: { $in: idList } } 249 | }); 250 | 251 | return this.Model.updateMany(query, remapModifier, options) 252 | .then(() => this._findOrGet(id, findParams)) 253 | .then(select(params, this.id)) 254 | .catch(errorHandler); 255 | }); 256 | } 257 | 258 | _update (id, data, params = {}) { 259 | if (Array.isArray(data) || id === null) { 260 | return Promise.reject( 261 | new errors.BadRequest('Not replacing multiple records. Did you mean `patch`?') 262 | ); 263 | } 264 | 265 | const { query, options } = this._multiOptions(id, params); 266 | 267 | return this.Model.replaceOne(query, this._normalizeId(id, data), options) 268 | .then(() => this._findOrGet(id, params)) 269 | .then(select(params, this.id)) 270 | .catch(errorHandler); 271 | } 272 | 273 | _remove (id, params = {}) { 274 | let { query, options } = this._multiOptions(id, params); 275 | 276 | if (params.collation) { 277 | query = Object.assign(query, { collation: params.collation }); 278 | } 279 | 280 | const findParams = Object.assign({}, params, { 281 | paginate: false, 282 | query: params.query 283 | }); 284 | 285 | return this._findOrGet(id, findParams) 286 | .then(items => { 287 | return this.Model.deleteMany(query, options) 288 | .then(() => items) 289 | .then(select(params, this.id)); 290 | }).catch(errorHandler); 291 | } 292 | } 293 | 294 | module.exports = function init (options) { 295 | return new Service(options); 296 | }; 297 | 298 | module.exports.Service = Service; 299 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feathers-mongodb", 3 | "description": "Feathers MongoDB service", 4 | "version": "6.4.1", 5 | "homepage": "https://github.com/feathersjs-ecosystem/feathers-mongodb", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/feathersjs-ecosystem/feathers-mongodb.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/feathersjs-ecosystem/feathers-mongodb/issues" 12 | }, 13 | "license": "MIT", 14 | "keywords": [ 15 | "feathers", 16 | "feathers-plugin", 17 | "REST", 18 | "Socket.io", 19 | "realtime", 20 | "mongo", 21 | "mongoskin", 22 | "mongodb", 23 | "service" 24 | ], 25 | "author": { 26 | "name": "Feathers contributors", 27 | "email": "hello@feathersjs.com", 28 | "url": "http://feathersjs.com" 29 | }, 30 | "contributors": [ 31 | "Eric Kryski (http://erickryski.com)", 32 | "David Luecke (http://neyeon.com)", 33 | "Marshall Thompson " 34 | ], 35 | "main": "lib/", 36 | "types": "types", 37 | "files": [ 38 | "CHANGELOG.md", 39 | "LICENSE", 40 | "README.md", 41 | "lib/**", 42 | "types/**", 43 | "*.d.ts", 44 | "*.js" 45 | ], 46 | "scripts": { 47 | "postpublish": "git push origin --tags && npm run changelog && git push origin", 48 | "changelog": "github_changelog_generator --user feathersjs-ecosystem --project feathers-mongodb && git add CHANGELOG.md && git commit -am \"Updating changelog\"", 49 | "release:patch": "npm version patch && npm publish", 50 | "release:minor": "npm version minor && npm publish", 51 | "release:major": "npm version major && npm publish", 52 | "lint": "semistandard --fix", 53 | "dtslint": "dtslint types", 54 | "update-dependencies": "ncu -u", 55 | "mocha": "mocha --recursive test/ --exit", 56 | "coverage": "nyc npm run mocha", 57 | "test": "npm run lint && npm run dtslint && npm run coverage", 58 | "mongodb": "run-rs -v 4.0.0" 59 | }, 60 | "semistandard": { 61 | "env": [ 62 | "mocha" 63 | ] 64 | }, 65 | "engines": { 66 | "node": ">= 8" 67 | }, 68 | "dependencies": { 69 | "@feathersjs/adapter-commons": "^4.5.11", 70 | "@feathersjs/commons": "^4.5.11", 71 | "@feathersjs/errors": "^4.5.11" 72 | }, 73 | "devDependencies": { 74 | "@feathersjs/adapter-tests": "^4.5.11", 75 | "@feathersjs/express": "^4.5.11", 76 | "@feathersjs/feathers": "^4.5.11", 77 | "@feathersjs/socketio": "^4.5.11", 78 | "chai": "^4.3.4", 79 | "dtslint": "^4.2.1", 80 | "mocha": "^9.1.3", 81 | "mongodb": "^4.2.2", 82 | "npm-check-updates": "^12.0.5", 83 | "nyc": "^15.1.0", 84 | "run-rs": "^0.7.5", 85 | "semistandard": "^16.0.1", 86 | "typescript": "^4.5.4" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { MongoClient, ObjectID } = require('mongodb'); 3 | const adapterTests = require('@feathersjs/adapter-tests'); 4 | 5 | const feathers = require('@feathersjs/feathers'); 6 | const errors = require('@feathersjs/errors'); 7 | 8 | const service = require('../lib'); 9 | const testSuite = adapterTests([ 10 | '.options', 11 | '.events', 12 | '._get', 13 | '._find', 14 | '._create', 15 | '._update', 16 | '._patch', 17 | '._remove', 18 | '.get', 19 | '.get + $select', 20 | '.get + id + query', 21 | '.get + NotFound', 22 | '.find', 23 | '.remove', 24 | '.remove + $select', 25 | '.remove + id + query', 26 | '.remove + multi', 27 | '.update', 28 | '.update + $select', 29 | '.update + id + query', 30 | '.update + NotFound', 31 | '.update + query + NotFound', 32 | '.patch', 33 | '.patch + $select', 34 | '.patch + id + query', 35 | '.patch multiple', 36 | '.patch multi query changed', 37 | '.patch + NotFound', 38 | '.patch multi query same', 39 | '.patch + query + NotFound', 40 | '.create', 41 | '.create + $select', 42 | '.create multi', 43 | 'internal .find', 44 | 'internal .get', 45 | 'internal .create', 46 | 'internal .update', 47 | 'internal .patch', 48 | 'internal .remove', 49 | '.find + equal', 50 | '.find + equal multiple', 51 | '.find + $sort', 52 | '.find + $sort + string', 53 | '.find + $limit', 54 | '.find + $limit 0', 55 | '.find + $skip', 56 | '.find + $select', 57 | '.find + $or', 58 | '.find + $in', 59 | '.find + $nin', 60 | '.find + $lt', 61 | '.find + $lte', 62 | '.find + $gt', 63 | '.find + $gte', 64 | '.find + $ne', 65 | '.find + $gt + $lt + $sort', 66 | '.find + $or nested + $sort', 67 | '.find + paginate', 68 | '.find + paginate + $limit + $skip', 69 | '.find + paginate + $limit 0', 70 | '.find + paginate + params', 71 | '.get + id + query id', 72 | '.remove + id + query id', 73 | '.update + id + query id', 74 | '.patch + id + query id' 75 | ]); 76 | 77 | describe('Feathers MongoDB Service', () => { 78 | const app = feathers(); 79 | 80 | let db; 81 | let mongoClient; 82 | 83 | before(async () => { 84 | const client = await MongoClient.connect('mongodb://localhost:27017/feathers-test', { 85 | useNewUrlParser: true 86 | }); 87 | 88 | mongoClient = client; 89 | db = client.db('feathers-test'); 90 | 91 | app.use('/people', service({ 92 | events: ['testing'] 93 | })).use('/people-customid', service({ 94 | Model: db.collection('people-customid'), 95 | id: 'customid', 96 | events: ['testing'] 97 | })).use('/people-estimated-count', service({ 98 | Model: db.collection('people-estimated-count'), 99 | events: ['testing'], 100 | useEstimatedDocumentCount: true 101 | })); 102 | 103 | app.service('people').Model = db.collection('people'); 104 | 105 | db.collection('people-customid').deleteMany(); 106 | db.collection('people').deleteMany(); 107 | db.collection('todos').deleteMany(); 108 | 109 | db.collection('people').createIndex( 110 | { name: 1 }, 111 | { partialFilterExpression: { team: 'blue' } } 112 | ); 113 | }); 114 | 115 | after(() => db.dropDatabase().then(() => mongoClient.close())); 116 | 117 | it('is CommonJS compatible', () => 118 | expect(typeof require('../lib')).to.equal('function') 119 | ); 120 | 121 | describe('Initialization', () => { 122 | describe('when missing options', () => { 123 | it('throws an error', () => 124 | expect(service.bind(null)).to.throw('MongoDB options have to be provided') 125 | ); 126 | }); 127 | 128 | describe('when missing the id option', () => { 129 | it('sets the default to be _id', () => 130 | expect(service({ Model: db }).id).to.equal('_id') 131 | ); 132 | }); 133 | }); 134 | 135 | describe('Service utility functions', () => { 136 | describe('objectifyId', () => { 137 | it('returns an ObjectID instance for a valid ID', () => { 138 | const id = new ObjectID(); 139 | const result = service({ Model: db })._objectifyId(id.toString(), '_id'); 140 | expect(result).to.be.instanceof(ObjectID); 141 | expect(result).to.deep.equal(id); 142 | }); 143 | 144 | it('does not return an ObjectID instance for an invalid ID', () => { 145 | const id = 'non-valid object id'; 146 | const result = service({ Model: db })._objectifyId(id.toString(), '_id'); 147 | expect(result).to.not.be.instanceof(ObjectID); 148 | expect(result).to.deep.equal(id); 149 | }); 150 | }); 151 | 152 | describe('_multiOptions', () => { 153 | const params = { 154 | query: { 155 | age: 21 156 | }, 157 | options: { 158 | limit: 5 159 | } 160 | }; 161 | 162 | it('returns valid result when passed an ID', () => { 163 | const id = new ObjectID(); 164 | const result = service({ Model: db })._multiOptions(id, params); 165 | expect(result).to.be.an('object'); 166 | expect(result).to.include.all.keys(['query', 'options']); 167 | expect(result.query).to.deep.equal(Object.assign({}, params.query, { $and: [{ _id: id }] })); 168 | expect(result.options).to.deep.equal(Object.assign({}, params.options, { multi: false })); 169 | }); 170 | 171 | it('returns original object', () => { 172 | const result = service({ Model: db })._multiOptions(null, params); 173 | expect(result).to.be.an('object'); 174 | expect(result).to.include.all.keys(['query', 'options']); 175 | expect(result.query).to.deep.equal(params.query); 176 | expect(result.options).to.deep.equal(Object.assign({}, params.options, { multi: true })); 177 | }); 178 | }); 179 | 180 | describe('_options', () => { 181 | const params = { 182 | query: { 183 | age: 21 184 | }, 185 | options: { 186 | limit: 5 187 | } 188 | }; 189 | 190 | it('returns original object', () => { 191 | const result = service({ Model: db })._options(params); 192 | expect(result).to.be.an('object'); 193 | expect(result).to.include.all.keys(['options', 'filters', 'query', 'paginate']); 194 | expect(result.query).to.deep.equal(params.query); 195 | expect(result.options).to.deep.equal(Object.assign({}, params.options)); 196 | }); 197 | }); 198 | 199 | describe('getSelect', () => { 200 | const projectFields = { name: 1, age: 1 }; 201 | const selectFields = ['name', 'age']; 202 | 203 | it('returns Mongo project object when an array is passed', () => { 204 | const result = service({ Model: db })._getSelect(selectFields); 205 | expect(result).to.be.an('object'); 206 | expect(result).to.deep.equal(projectFields); 207 | }); 208 | 209 | it('returns original object', () => { 210 | const result = service({ Model: db })._getSelect(projectFields); 211 | expect(result).to.be.an('object'); 212 | expect(result).to.deep.equal(projectFields); 213 | }); 214 | }); 215 | }); 216 | 217 | describe('Special collation param', () => { 218 | let peopleService, people; 219 | 220 | function indexOfName (results, name) { 221 | let index; 222 | results.every(function (person, i) { 223 | if (person.name === name) { 224 | index = i; 225 | return false; 226 | } 227 | return true; 228 | }); 229 | return index; 230 | } 231 | 232 | beforeEach(async () => { 233 | peopleService = app.service('/people'); 234 | peopleService.options.multi = true; 235 | peopleService.options.disableObjectify = true; 236 | people = await peopleService.create([ 237 | { name: 'AAA' }, { name: 'aaa' }, { name: 'ccc' } 238 | ]); 239 | }); 240 | 241 | afterEach(async () => { 242 | peopleService.options.multi = false; 243 | await Promise.all([ 244 | peopleService.remove(people[0]._id), 245 | peopleService.remove(people[1]._id), 246 | peopleService.remove(people[2]._id) 247 | ]).catch(() => {}); 248 | }); 249 | 250 | it('queries for ObjectId in find', async () => { 251 | const person = await peopleService.create({ name: 'Coerce' }); 252 | const results = await peopleService.find({ 253 | query: { 254 | _id: new ObjectID(person._id) 255 | } 256 | }); 257 | 258 | expect(results).to.have.lengthOf(1); 259 | 260 | await peopleService.remove(person._id); 261 | }); 262 | 263 | it('works with normal string _id', async () => { 264 | const person = await peopleService.create({ 265 | _id: 'lessonKTDA08', 266 | name: 'Coerce' 267 | }); 268 | const result = await peopleService.get(person._id); 269 | 270 | expect(result.name).to.equal('Coerce'); 271 | 272 | await peopleService.remove(person._id); 273 | }); 274 | 275 | it('sorts with default behavior without collation param', async () => { 276 | const results = await peopleService.find({ query: { $sort: { name: -1 } } }); 277 | 278 | expect(indexOfName(results, 'aaa')).to.be.below(indexOfName(results, 'AAA')); 279 | }); 280 | 281 | it.skip('sorts using collation param if present', async () => { 282 | const results = await peopleService.find({ 283 | query: { $sort: { name: -1 } }, 284 | collation: { locale: 'en', strength: 1 } 285 | }); 286 | 287 | expect(indexOfName(results, 'AAA')).to.be.below(indexOfName(results, 'aaa')); 288 | }); 289 | 290 | it('removes with default behavior without collation param', async () => { 291 | await peopleService.remove(null, { query: { name: { $gt: 'AAA' } } }); 292 | 293 | const results = await peopleService.find(); 294 | 295 | expect(results).to.have.lengthOf(1); 296 | expect(results[0].name).to.equal('AAA'); 297 | }); 298 | 299 | it('removes using collation param if present', async () => { 300 | await peopleService.remove(null, { 301 | query: { name: { $gt: 'AAA' } }, 302 | collation: { locale: 'en', strength: 1 } 303 | }); 304 | 305 | const results = await peopleService.find(); 306 | 307 | expect(results).to.have.lengthOf(3); 308 | }); 309 | 310 | it('updates with default behavior without collation param', async () => { 311 | const query = { name: { $gt: 'AAA' } }; 312 | 313 | const result = await peopleService.patch(null, { age: 99 }, { query }); 314 | 315 | expect(result).to.have.lengthOf(2); 316 | result.forEach(person => { 317 | expect(person.age).to.equal(99); 318 | }); 319 | }); 320 | 321 | it('updates using collation param if present', async () => { 322 | const result = await peopleService.patch(null, { age: 110 }, { 323 | query: { name: { $gt: 'AAA' } }, 324 | collation: { locale: 'en', strength: 1 } 325 | }); 326 | 327 | expect(result).to.have.lengthOf(1); 328 | expect(result[0].name).to.equal('ccc'); 329 | }); 330 | 331 | it('pushes to an array using patch', async () => { 332 | const result = await peopleService.patch(null, { $push: { friends: 'Adam' } }, { 333 | query: { name: { $gt: 'AAA' } } 334 | }); 335 | 336 | expect(result[0].friends).to.have.lengthOf(1); 337 | 338 | const patched = await peopleService.patch(null, { 339 | $push: { friends: 'Bell' } 340 | }, { query: { name: { $gt: 'AAA' } } }); 341 | 342 | expect(patched[0].friends).to.have.lengthOf(2); 343 | }); 344 | 345 | it('overrides default index selection using hint param if present', async () => { 346 | const indexed = await peopleService.create({ name: 'Indexed', team: 'blue' }); 347 | 348 | const result = await peopleService.find({ query: { }, hint: { name: 1 } }); 349 | 350 | expect(result).to.have.lengthOf(1); 351 | 352 | await peopleService.remove(indexed._id); 353 | }); 354 | }); 355 | 356 | testSuite(app, errors, 'people', '_id'); 357 | testSuite(app, errors, 'people-customid', 'customid'); 358 | testSuite(app, errors, 'people-estimated-count', '_id'); 359 | }); 360 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 3.7 2 | import { Params, Paginated, Id, NullableId } from '@feathersjs/feathers'; 3 | import { AdapterService, ServiceOptions, InternalServiceMethods } from '@feathersjs/adapter-commons'; 4 | import { Collection } from 'mongodb'; 5 | 6 | export interface MongoDBServiceOptions extends ServiceOptions { 7 | Model: Collection; 8 | } 9 | 10 | export class Service extends AdapterService implements InternalServiceMethods { 11 | Model: Collection; 12 | options: MongoDBServiceOptions; 13 | 14 | constructor(config?: Partial); 15 | 16 | _find(params?: Params): Promise>; 17 | _get(id: Id, params?: Params): Promise; 18 | _create(data: Partial | Array>, params?: Params): Promise; 19 | _update(id: NullableId, data: T, params?: Params): Promise; 20 | _patch(id: NullableId, data: Partial, params?: Params): Promise; 21 | _remove(id: NullableId, params?: Params): Promise; 22 | } 23 | 24 | declare const mongodb: ((config?: Partial) => Service); 25 | export default mongodb; 26 | -------------------------------------------------------------------------------- /types/index.test.ts: -------------------------------------------------------------------------------- 1 | import { MongoClient } from 'mongodb'; 2 | import { default as mongodb, Service } from 'feathers-mongodb'; 3 | 4 | MongoClient.connect('mongodb://localhost:27017/feathers').then(client => { 5 | const service1 = mongodb({ 6 | Model: client.db('feathers').collection('messages') 7 | }); 8 | 9 | const service2 = new Service({ 10 | Model: client.db('feathers').collection('messages'), 11 | events: ['test'] 12 | }); 13 | 14 | service2._get(2); 15 | 16 | service1.Model = client.db('feathers').collection('messages'); 17 | }); 18 | -------------------------------------------------------------------------------- /types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "lib": ["es6"], 5 | "target": "es6", 6 | "noImplicitAny": true, 7 | "noImplicitThis": true, 8 | "strictNullChecks": true, 9 | "strictFunctionTypes": true, 10 | "noEmit": true, 11 | "skipLibCheck": true, 12 | // If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index". 13 | // If the library is global (cannot be imported via `import` or `require`), leave this out. 14 | "baseUrl": ".", 15 | "paths": { "feathers-mongodb": ["."] } 16 | } 17 | } -------------------------------------------------------------------------------- /types/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", // Or "dtslint/dt.json" if on DefinitelyTyped 3 | "rules": { 4 | "indent": [true, "spaces"] 5 | } 6 | } --------------------------------------------------------------------------------