Skip to content

Commit

Permalink
Merge pull request #584 from strongloop/fix/filter
Browse files Browse the repository at this point in the history
fix: sanitizes extra dollar signs for operators
  • Loading branch information
agnes512 authored Jul 10, 2020
2 parents b12633b + c839406 commit 319d5f0
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ If you run a MongoDB with authentification ([Docker's example here](https://gith
<td>allowExtendedOperators</td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Set to <code>true</code> to enable using MongoDB operators such as <code>$currentDate, $inc, $max, $min, $mul, $rename, $setOnInsert, $set, $unset, $addToSet, $pop, $pullAll, $pull, $pushAll, $push</code>, and <code>$bit</code>.</td>
<td>Set to <code>true</code> to enable using MongoDB operators such as <code>$currentDate, $inc, $max, $min, $mul, $rename, $setOnInsert, $set, $unset, $addToSet, $pop, $pullAll, $pull, $push</code>, and <code>$bit</code>. See <a href="https://loopback.io/doc/en/lb4/MongoDB-connector.html#update-operators" class="external-link" rel="nofollow">Update Operators</a> section below</td>
</tr>
<tr>
<td>enableGeoIndexing</td>
Expand Down Expand Up @@ -249,6 +249,32 @@ The .loopbackrc file is in JSON format, for example:

</details>

## Update Operators

Except the comparison and logical operators LoopBack supports in the [operator list](https://loopback.io/doc/en/lb4/Where-filter.html#operators) of `Where` filter, you can also enable [MongoDB update operators](https://docs.mongodb.com/manual/reference/operator/update/) for `update*` methods by setting the flag `allowExtendedOperators` to `true` in the datasource configuration.

Here is an example of updating the price for all the products under category `furniture` if their current price is lower than 100:

```
await productRepo.updateAll({ $max: { price: 100 }}, { category: {eq: 'furniture'} // where clause goes in here });
```

<details><summary markdown="span"><strong>For LoopBack 3 users</strong></summary>

```
Product.updateAll(
{ category: {eq: 'furniture'} // where clause goes in here },
{$max: {price: 100}},
options,
function(err, updateproducts) {
...
```

</details>

{% include tip.html content="you **will not** need the dollar sign `'$'` for operators in the Where
clause." %}

## Handling ObjectId

MongoDB uses `ObjectId` for its primary key, which is an object instead of a
Expand Down
13 changes: 12 additions & 1 deletion lib/mongodb.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@ MongoDB.prototype.parseUpdateData = function(modelName, data, options) {
'$pop',
'$pullAll',
'$pull',
'$pushAll',
'$push',
// Bitwise operator
'$bit',
Expand Down Expand Up @@ -993,6 +992,7 @@ MongoDB.prototype.buildWhere = function(modelName, where, options) {
const modelCtor = self._models[modelName];

if (spec) {
spec = trimLeadingDollarSigns(spec);
if (spec === 'between') {
query[k] = {$gte: cond[0], $lte: cond[1]};
} else if (spec === 'inq') {
Expand Down Expand Up @@ -1994,6 +1994,17 @@ function isObjectIDProperty(modelCtor, propDef, value, options) {
}
}

/**
* Removes extra dollar sign '$' for operators
*
* @param {*} spec the operator for Where filter
*/
function trimLeadingDollarSigns(spec) {
return spec.replace(/^(\$)+/, '');
}

exports.trimLeadingDollarSigns = trimLeadingDollarSigns;

function sanitizeFilter(filter, options) {
options = Object.assign({}, options);
if (options && options.disableSanitization) return filter;
Expand Down
26 changes: 25 additions & 1 deletion test/mongodb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const testUtils = require('../lib/test-utils');
const async = require('async');
const sinon = require('sinon');
const sanitizeFilter = require('../lib/mongodb').sanitizeFilter;
const trimLeadingDollarSigns = require('../lib/mongodb').trimLeadingDollarSigns;

const GeoPoint = require('loopback-datasource-juggler').GeoPoint;

Expand Down Expand Up @@ -1485,7 +1486,7 @@ describe('mongodb connector', function() {
should.not.exist(err);
updatedusers.should.have.property('count', 1);

User.find({where: {name: 'Simon'}}, function(
User.find({where: {name: {$eq: 'Simon'}}}, function(
err,
foundusers,
) {
Expand Down Expand Up @@ -3726,6 +3727,29 @@ describe('mongodb connector', function() {
});
});

context('trimLeadingDollarSigns', () =>{
it('removes an extra leading dollar sign in ths operators', () => {
const spec = '$eq';
const updatedSpec = trimLeadingDollarSigns(spec);
updatedSpec.should.equal('eq');
});
it('removes extra leading dollar signs in ths operators', () => {
const spec = '$$eq';
const updatedSpec = trimLeadingDollarSigns(spec);
updatedSpec.should.equal('eq');
});

it('remains the same if the input does not contain any dollar signs', () => {
const spec = 'eq';
const updatedSpec = trimLeadingDollarSigns(spec);
updatedSpec.should.equal(spec);
});
it('remains the same if the input does not start with dollar signs', () => {
const spec = 'eq$';
const updatedSpec = trimLeadingDollarSigns(spec);
updatedSpec.should.equal(spec);
});
});
context('sanitizeFilter()', () => {
it('returns filter if not an object', () => {
const input = false;
Expand Down

0 comments on commit 319d5f0

Please sign in to comment.