Skip to content

Commit

Permalink
feat: add projection
Browse files Browse the repository at this point in the history
  • Loading branch information
saisilinus committed Apr 8, 2022
1 parent a2331a2 commit 488405a
Show file tree
Hide file tree
Showing 19 changed files with 68 additions and 78 deletions.
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ cp .env.example .env
- [Logging](#logging)
- [Custom Mongoose Plugins](#custom-mongoose-plugins)
- [To JSON Plugin](#tojson)
- [Hide to JSON Plugin](#hidetojson)
- [Paginate Plugin](#paginate)
- [Linting](#linting)
- [Contributing](#contributing)
Expand Down Expand Up @@ -154,9 +153,9 @@ Manually fix remaining linting errors in the JS files
## Linting Errors After Compiling

After compiling, you are likely to get linting errors since some were disabled through comments in TypeScript files. Currently, the following files get linting errors after running `yarn compile`:
- dist/modules/errors/error.js: fix -> `// eslint-disable-next-line no-unused-vars`
- dist/modules/toJSON/hideToJSON.plugin.js: fix -> `/* eslint-disable no-param-reassign */`
- dist/modules/toJSON/toJSON.plugin.js: fix -> `/* eslint-disable no-param-reassign */`
- dist/modules/errors/error.js: fix -> disable `no-unused-vars` for the line
- dist/modules/toJSON/hideToJSON.plugin.js: fix -> disable `no-param-reassign` for the whole file
- dist/modules/toJSON/toJSON.plugin.js: fix -> disable `no-param-reassign` for the whole file

## Environment Variables

Expand Down Expand Up @@ -368,11 +367,11 @@ Note: API request information (request url, response code, timestamp, etc.) are

## Custom Mongoose Plugins

The app also contains 2 custom mongoose plugins that you can attach to any mongoose model schema. You can find the plugins in `src/models/plugins`.
The app also contains 3 custom mongoose plugins that you can attach to any mongoose model schema. You can find the plugins in `src/models/plugins`.

```javascript
const mongoose = require('mongoose');
const { toJSON, paginate } = require('./plugins');
const { toJSON, paginate, hideToJSON } = require('./plugins');

const userSchema = mongoose.Schema(
{
Expand All @@ -384,6 +383,11 @@ const userSchema = mongoose.Schema(
userSchema.plugin(toJSON);
userSchema.plugin(paginate);

/* Use hideToJSON f you want to change fields to be hidden by toJSON in every request
NOTE: You can't use both toJSON and hideToJSON for the same schema*/
userSchema.plugin(hideToJSON);


const User = mongoose.model('User', userSchema);
```

Expand All @@ -394,14 +398,6 @@ The toJSON plugin applies the following changes in the toJSON transform call:
- removes \_\_v, createdAt, updatedAt, and any schema path that has private: true
- replaces \_id with id

### hideToJSON

The hideToJSON plugin applies the following changes in the toJSON transform call:

- removes \_\_v, createdAt, updatedAt
- replaces \_id with id
- allows user to dynamically hide field by passing schema paths

### paginate

The paginate plugin adds the `paginate` static method to the mongoose schema.
Expand All @@ -424,9 +420,16 @@ const options = {
sortBy: 'name:desc', // sort order
limit: 5, // maximum results per page
page: 2, // page number
projectBy: 'name:hide, role:hide', // fields to hide or include in the results
};
```

The `projectBy` option can include multiple criteria (separated by a comma) but cannot include and exclude fields at the same time. Check out the following examples:

- [x] `name:hide, role:hide` should work
- [x] `name:include, role:include` should work
- [ ] `name:include, role:hide` will not work

The plugin also supports sorting by multiple criteria (separated by a comma): `sortBy: name:desc,role:asc`

The `paginate` method returns a Promise, which fulfills with an object having the following properties:
Expand Down
14 changes: 13 additions & 1 deletion dist/modules/paginate/paginate.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const paginate = (schema) => {
* @param {string} [options.populate] - Populate data fields. Hierarchy of fields should be separated by (.). Multiple populating criteria should be separated by commas (,)
* @param {number} [options.limit] - Maximum number of results per page (default = 10)
* @param {number} [options.page] - Current page (default = 1)
* @param {string} [options.projectBy] - Fields to hide or include (default = '')
* @returns {Promise<QueryResult>}
*/
schema.static('paginate', async function (filter, options) {
Expand All @@ -29,11 +30,22 @@ const paginate = (schema) => {
} else {
sort = 'createdAt';
}
let project = '';
if (options.projectBy) {
const projectionCriteria = [];
options.projectBy.split(',').forEach((projectOption) => {
const [key, include] = projectOption.split(':');
projectionCriteria.push((include === 'hide' ? '-' : '') + key);
});
project = projectionCriteria.join(' ');
} else {
project = '-createdAt -updatedAt';
}
const limit = options.limit && parseInt(options.limit.toString(), 10) > 0 ? parseInt(options.limit.toString(), 10) : 10;
const page = options.page && parseInt(options.page.toString(), 10) > 0 ? parseInt(options.page.toString(), 10) : 1;
const skip = (page - 1) * limit;
const countPromise = this.countDocuments(filter).exec();
let docsPromise = this.find(filter).sort(sort).skip(skip).limit(limit);
let docsPromise = this.find(filter).sort(sort).skip(skip).limit(limit).select(project);
if (options.populate) {
options.populate.split(',').forEach((populateOption) => {
docsPromise = docsPromise.populate(
Expand Down
2 changes: 1 addition & 1 deletion dist/modules/paginate/paginate.plugin.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 0 additions & 23 deletions dist/modules/toJSON/hideToJSON.plugin.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/modules/toJSON/hideToJSON.plugin.js.map

This file was deleted.

5 changes: 2 additions & 3 deletions dist/modules/toJSON/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import toJSON from './toJSON.plugin';
import hideToJSON from './hideToJSON.plugin';

export { toJSON, hideToJSON };
// eslint-disable-next-line import/prefer-default-export
export { toJSON };
// # sourceMappingURL=index.js.map
2 changes: 1 addition & 1 deletion dist/modules/toJSON/index.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/modules/user/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const createUser = catchAsync(async (req, res) => {
});
export const getUsers = catchAsync(async (req, res) => {
const filter = pick(req.query, ['name', 'role']);
const options = pick(req.query, ['sortBy', 'limit', 'page']);
const options = pick(req.query, ['sortBy', 'limit', 'page', 'projectBy']);
const result = await userService.queryUsers(filter, options);
res.send(result);
});
Expand Down
2 changes: 1 addition & 1 deletion dist/modules/user/user.controller.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/modules/user/user.validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const getUsers = {
name: Joi.string(),
role: Joi.string(),
sortBy: Joi.string(),
projectBy: Joi.string(),
limit: Joi.number().integer(),
page: Joi.number().integer(),
}),
Expand Down

0 comments on commit 488405a

Please sign in to comment.