filter-objects v2.1.1
filter-objects.js
###Use a pattern object to simply filter an array of objects or match on a single object.
Features:
- Simple 'pattern object' approach eg:
filter({fido: {color: 'black'}},arrayOfPetObjs) - Deep object property testing
- Can define filter properties & options prior to filter call for better performance
- Filter with regular expressions - on either the pattern object or targe objects
- Filter options and functions can be defined for each object property being tested
- Custom filter functions
- Variables in the pattern and target objects
Install with:
npm install filter-objectsbower install filter-objects
Examples
// find which pets have 4 paws
var fos = require('filter-objects');
var pets = [
{ name: 'fido',
paws: {color: 'gray', count: 3},
},
{ name: 'rover',
paws: {color: 'white', count: 4},
},
];
fos.filter({paws:{count: 4}}, pets);
//[{ name: 'rover', paws: {color: 'white', count: 4}]; Filter an array of objects with better performance. Calling makeFilterFn to create your filter first embeds as much as the logic as possible into the returned filter function so that it doesn't need to be performed at the time of the actual filter call.
var filter = fos.makeFilterFn(['paws.count']);
filter({paws:{count: 4}}, pets);
//[{ name: 'rover', paws: {color: 'white', count: 4}]; Filter by regular expression - on either the pattern object or target objects (the array of objects being filtered).
var options = {regExpMatch: true};
var props = ["tail.color"];
var filter = fos.makeFilterFn(props,options);
var pObj = {tail: {color: /gr.y/}};
var tObjs = [
{type: "dog", paws: {count: 4}, tail: {count: 1, color: "black"}},
{type: "rabbit", paws: {count: 3}, tail: {count: 1, color: "white"}},
{type: "cat", paws: {count: 4}, tail: {color: "gray"}},
{type: "lizard", paws: {count: 0}, tail: {color: "grey"}},];
filter(pObj, tObjs);
// [{type: "cat", paws: {count: 4}, tail: {color: "gray"}},
// {type: "lizard", paws: {count: 0}, tail: {color: "grey"}}]
// OR filter reversing the reg exp match where the reg exp is on the
// target objects and being tested against the pattern object.
var options = {regExpMatch: true, regExpReverse: true};
var props = ["tail.color"];
var filter = fos.makeFilterFn(props,options);
var pObj = {tail: {color: 'gray'}};
var tObjs = [
{type: "dog", paws: {count: 4}, tail: {count: 1, color: "black"}},
{type: "rabbit", paws: {count: 3}, tail: {count: 1, color: "white"}},
{type: "cat", paws: {count: 4}, tail: {color: "gray"}},
{type: "lizard", paws: {count: 0}, tail: {color: /gr.y/}},];
filter(pObj, tObjs);
// [{type: "cat", paws: {count: 4}, tail: {color: "gray"}},
// {type: "lizard", paws: {count: 0}, tail: {color: /gr.y/}}]
// Properties to test do not cascade to include nested object properties so
// `propsToTest=['tail'] would not have the same result. See propsToTest section.See performance section for performance info.
Tested on latest versions of Node 0.10, 0.12, 4, 5 and 6.
API
Match and Filter Functions
Helper functions
Options for makeFilterFn and makeMatchFn
regExpMatch(Plus several related reg exp options)matchIfPObjPropMissingmatchIfTObjPropMissing- variables (
variablesInPObj,variablesInTObj) propMatchFn
filter(pObj, tObjs)
Returns a new array of tObjs that match the pObj based on default Options if called directly or the propsToTest and options parameters if this function was created with makeFilterFn. Call makeFilterFn to create this function for better performance.
Arguments
Examples
// find which pets have gray paws regardeless if 'gray' or 'grey'
var fos = require('filter-objects');
var pets = [
{ name: 'fido',
paws: {color: 'gray', count: 3},
},
{ name: 'rover',
paws: {color: 'white', count: 4},
},
];
// create the pattern object
var pObj = {paws:{color: /gr[a,e]y/}};
// select properties and options to test
var propsToTest = ['paws.color'];
var options = {regExpMatch: true};
// create the filter function
var filter = fos.makeFilterFn(propsToTest, options);
// filter
filter(pObj, pets);
// [ { name: 'fido', paws: { color: 'gray', count: 3 } } ] makeFilterFn(propsToTest, options)
Creates and returns a filter function that is configured to test the properties included in propsToTest using options to determine how properties are tested for a match between pObj and tObjs.
Arguments
propsToTestoptionsoptional Applies to each property inpropsToTestunlessoptionsvalues are included for properties inpropsToTest.optionsprecedence is (1)propsToTestoptionsvalues if set (2)optionsas included here as a parameter, otherwise (3)optionsdefault values.
Examples
See filter.
matches(pObj, tObj)
Tests pattern object against one object. Returns true if properties identified to be tested between pObj and tObj match; otherwise returns false.
Which properties are tested and if they match is determined by whether matches is called directly or created via the makeMatchFn.
If matches is created via makeMatchFn then the propsToTest and options parameters determine which properties are tested for match and how the properties are tested for match. Calling the resulting matches function created via makeMatchFn also provides better performance than calling matches directly.
If matches function is called directly without creating it via makeMatchFn, every property in the pObj object is tested for a match and all options values are default. Options cannot be modified if calling matches directly.
Arguments
Examples
// test if fido's tail color is gray
var fos = require('filter-objects');
var fido ={
tail: {color: 'gray', count: 1},
body: {color: 'black'},
housetrained: true};
var pObj = {tail: {color: 'gray'}};
fos.matches(pObj, fido); //true
});
// Or, create the matches function to include option
// such as regular expression matches.
// select the properties to be tested and the options
var propsToTest = ['tail.color'];
var options = {regExpMatch:true};
// create the custom match function
var matchFn = fos.makeMatchFn(propsToTest, options);
// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr.y/}};
// test it
matchFn(pObj, fido); // truemakeMatchFn(propsToTest, options)
Creates and returns a matches function that is configured to test the properties included in propsToTest and options to determine how properties are tested for a match. This created function will run faster than calling the matches function directly and allows for greater control, via propsToTest and options, of which properties are tested and how.
Arguments
propsToTestoptions- optional Applies to each property inpropsToTestunlessoptionsvalues are included for properties inpropsToTest.optionsprecedence is (1)propsToTestoptionsvalues if set (2)optionsas included here as a parameter, otherwise (3)optionsdefault values.
Examples
// test if fido has a gray tail regardless if grey or gray
var fos = require('filter-objects');
var fido ={ tail: {color: 'gray', count: 1}};
// select the properties to be tested and the options
var propsToTest = ['tail.color'];
var options = {regExpMatch:true};
// create the match function
var matchFn = fos.makeMatchFn(propsToTest, options);
// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr.y/}};
// test it
matchFn(pObj, fido); // true
});It would give the same result to set the options in propsToTest
var propsToTest = {'tail.color':{regExpMatch:true}};
var matchFn = fos.makeMatchFn(propsToTest); // options not included here
matchFn(pObj, fido) // true;pObj
"pattern object". Any object that is passed into a [matches](#matches) or [filter](#filter) function as the first parameter. It is used to test if it matches the [target object](#tObj)(tObj).
var fos = require('filter-objects');
// the target object here is fido
var fido ={
paws: {color: 'grey', count: 3},
tail: {color: 'gray', count: 1},
body: {color: 'black'},
housetrained: true};
// the pattern object
var pObj = {tail: {color: 'gray'}};
fos.matches(pObj, fido); //truetObj
"target object". Any object that is passed into a [matches](#matches) or [filter](#filter) (as an array) function as the second parameter. The target object or objects is/are the object(s) that is/are being tested against the pattern object to determine if it matches. See notes and example under [pObj](#pObj).
propsToTest
An array or object that contains property names and their assigned [options](#options) values, if any. Property names are strings and are in dot notation if nested; eg "tail.color" to identify the property in {tail: {color: black}}. Properties to test do not cascade to include nested object properties; see caution note at bottom of this section.
Can take one of the following forms:
an array of strings which are the property names to be tested.
optionsvalues cannot be specified for individual properties with this form. Example:['name', 'tail.color', 'housetrained']an array of objects, one for each property to be tested, each containing a 'name' property assigned to the property name to be tested, and option property key/values (optional). Example:
// test using default options for housetrained; tail.color using reg exp match [{name: 'housetrained'}, {name: 'tail.color', regExpMatch: true}]an array of objects, one for each property to be tested, each with one key which is the property name and an options object as its value. Example:
// test using default options for housetrained; tail.color using reg exp match [{'housetrained': {}}, {'tail.color': {regExpMatch: true}}]an array of combination of the above 3 (strings and objects). Example:
['housetrained', {name: 'tail.color', regExpMatch: true},{'paws':{regExpMatch: false}}]an object with property names as keys and
optionsobjects as the values. Example:// test using default options for housetrained; tail.color using reg exp match {'housetrained':{}, 'tail.color': {regExpMatch: true}}
CAUTION: Every nested object property to be tested must be included in propsToTest if they are to be tested discretely; ie, properties to be tested are not cascaded into nested objects. For example: if the target object is {name: 'fido',paws: {count: 4, color: 'black'}}, including 'paws' in propsToTest does not test paws.count and paws.color. It simply will test the object {count:4, color: 'black'} using the test properties you have established so if it is a regExp test and the pattern object is {paws:'.*color.*'}, it will match because the object is simply converted to a string. To test the properties in paws, include 'paws.count' and 'paws.color' specifically in propsToTest.
options
An object used to set the option values for match and filter functions.
//options properties & their default values
var options = {
regExpMatch: false, // match on regular expression in `pObj`
regExpReverse: false, // reg exp on the *`tObj`* and tests against the pObj
regExpIgnoreCase: false, // ignore case on reg exp match (str only)
regExpAnchorStart: false, // append "^" to beg of str for reg exp (str only)
regExpAnchorEnd: false, // append "$" to end of str for reg exp (str only)
matchIfPObjPropMissing: false, // matches if `pObj` property doesn't exist
matchIfTObjPropMissing: false, // matches if `tObj` property doesn't exist
matchIfBothPropMissing: false, // match on this property if BOTH tObj & pObj are missing
variablesAllowed: false, // replace var names with var values in `pObj` props
variablesInPObj: false, // substitute variables in prop value in pattern obj
variablesInTObj: false, // substitute variables in prop value in target obj
variables: {}, // object of variables with var names as keys
variablesStartStr: '~', // beg str in pObj prop value to find the var name
variablesEndStr: null, // end str in pObj prop value to find the var name
doNotCheckInherited: false, // do not include inherited properties
propMatchFn: null // function to call instead of std match function
}; regExpMatch
Property on the [options](#options) object that if equal to true, filter and matches functions will use the pObj property value as a regular expression to test against the tObj property. If the pattern object property value is a string, the string will be converted to a javascript regular expression.
- valid values:
true,false - default:
false
Example:
// test if fido has a gray tail regardless if grey or gray
var fos = require('filter-objects');
var fido ={
paws: {color: 'grey', count: 3},
tail: {color: 'gray', count: 1},
body: {color: 'black'},
housetrained: true};
// select the properties to be tested and the options
var propsToTest = ['tail.color'];
var options = {regExpMatch:true};
// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr[a,e]y/}};
// create the match function
var matchFn = fos.makeMatchFn(propsToTest, options);
// test it
matchFn(pObj, fido); // trueregExpReverse
Property on the [options](#options) object that reverses the regular expression test so that the tObj is a regular expression that will be tested against the pObj property.
Like all of the regExp options, this option is only considered if regExpMatch = true.
var options = {regExpMatch: true, regExpReverse: true};
var props = ["tail.color"];
var filter = fos.makeFilterFn(props,options);
var pObj = {tail: {color: 'gray'}};
var tObjs = [
{type: "dog", paws: {count: 4}, tail: {count: 1, color: "black"}},
{type: "rabbit", paws: {count: 3}, tail: {count: 1, color: "white"}},
{type: "cat", paws: {count: 4}, tail: {color: "gray"}},
{type: "lizard", paws: {count: 0}, tail: {color: /gr.y/}},];
filter(pObj, tObjs);
// [{type: "cat", paws: {count: 4}, tail: {color: "gray"}},
// {type: "lizard", paws: {count: 0}, tail: {color: /gr.y/}}]regExpIgnoreCase
Property on the [options](#options) object that if equal to true and [regExpMatch](#regExpMatch)===true and the pObj property value is a string, then when the pObj value is converted from a string to a regular expression object in matches and filter functions, the regular expression is included with the 'i' flag to ignore case on the regular expression match. This option value is only considered where the pObj property value is a string. If the pObj value is a regular expression object, then the ignore case flag can be included on that object; eg "/gray/i".
- valid values:
true,false - default:
falseLike all of the regExp options, this option is only considered ifregExpMatch=true.
Example:
// test if fido has a gray tail regardless if grey or Gray
var fos = require('filter-objects');
var fido ={
paws: {color: 'grey', count: 3},
tail: {color: 'Gray', count: 1},
body: {color: 'black'},
housetrained: true};
// select the properties to be tested and the options
var propsToTest = ['tail.color'];
var options = {regExpMatch:true, regExpIgnoreCase: true};
// include the regular expression as a string in the pattern object
var pObj = {tail:{color: 'gr[a,e]y'}};
// create the match function
var matchFn = fos.makeMatchFn(propsToTest, options);
// test it
matchFn(pObj, fido); // true
// and same approach with `filter`// regExpIgnoreCase does not apply if pObj property is a regular expression
var pObj = {tail:{color: /gr[a,e]y/}};
matchFn(pObj, fido, function(doesMatch){
console.log(doesMatch); // false
});
// use the 'i' flag on the regular expression object instead
var pObj = {tail:{color: /gr[a,e]y/i}};
matchFn(pObj, fido); // true
// and same approach with `filter`regExpAnchorStart
Property on the [options](#options) object that if equal to true and [regExpMatch](#regExpMatch)===true and the pObj property value is a string, then when the pObj value is converted from a string to a regular expression object in matches and filter functions, it includes a '^' prepended to pObj string value. This option value is only considered where the pObj is a string. If the pObj property value is a regular expression object, then the ^ can be included in the regular expression; eg, /^gray/.
- valid values:
true,false default:
falseThis option will rarely (ever?) be needed as this can also be achieved with a
pObjvalue that is a string by simply including the ^ in the string (without settingregExpAnchorStart=true).Like all of the regExp options, this option is only considered if
regExpMatch=true.These 3 would yield the same result:
var pObj = {tail: {color: '^gray'}} var options = {regExpMatch: true}
```javascript
var pObj = {tail: {color: 'gray'}}
var options = {regExpMatch: true, regExpAnchorStart: true}var pObj = {tail: {color: /^gray/}}
var options = {regExpMatch: true}regExpAnchorEnd
Property on the [options](#options) object that if equal to true and [regExpMatch](#regExpMatch)===true and the pObj property value is a string, then when the pObj value is converted from a string to a regular expression object in matches and filter functions, it includes a '$' appended to the end of the pObj string value. This option value is only considered where the pObj is a string. If the pObj property value is a regular expression object, then the $ can be included in the regular expression; eg, /gray$/.
- valid values:
true,false default:
falseThis option will rarely (ever?) be needed as this can also be achieved with a
pObjvalue that is a string by simply including the $ in the string (without settingregExpAnchorEnd=true).Like all of the regExp options, this option is only considered if
regExpMatch=true.These 3 would yield the same result:
var pObj = {tail: {color: 'gray$'}} var options = {regExpMatch: true}
```javascript
var pObj = {tail: {color: 'gray'}}
var options = {regExpMatch: true, regExpAnchorEnd: true}var pObj = {tail: {color: /gray$/}}
var options = {regExpMatch: true}matchIfTObjPropMissing
Property on the [options](#options) object that if equal to true, filter and matches functions will return true for the given property's match test if the property being tested does not exist on tObj.
- valid values:
true,false - default:
false
Example:
// find which pets have a role of guarddog and (the breed is chihuahua or
// breed is not defined)
var fos = require('filter-objects');
var pets = [
{name: 'growler',
breed: 'chihuahua',
role: 'guarddog'},
{name: 'fido',
breed: 'lab',
role: 'pet'},
{name: 'duchy',
role: 'guarddog'},
{name: 'bruiser',
breed: 'chihuahua',
role: 'cuddler'},
]
// request is the tObj
var pObj = {role:'guarddog', breed: 'chihuahua'};
// select properties to test; role with default options
var propsToTest =
{role: {}, breed: {matchIfTObjPropMissing: true}};
// create the filter function
var filter = fos.makeFilterFn(propsToTest);
// filter
filter(pObj, pets);
// [ { name: 'growler'...},{name: 'duchy'...} ]matchIfPObjPropMissing
Property on the [options](#options) object that if equal to true, filter and matches functions will return truefor the given property's match test if the property being tested does not exist on pObj.
- valid values:
true,false - default:
false
Example:
// find which pets match a request with a role of guarddog and
// (the breed is chihuahua or breed is not defined)
var fos = require('filter-objects');
// pets are the `pObjs` in this case to match on their regular expressions
var pets = [
{name: 'growler',
breed: 'chihuahua',
path: /.*role=guarddog.*/},
{name: 'fido',
breed: 'lab',
path: /.*role=pet.*/},
{name: 'duchy',
path: /.*role=guarddog.*/},
{name: 'bruiser',
breed: 'chihuahua',
path: /.*role=cuddler.*/},
]
// request is the tObj
var request = {path: '/pets?role=guarddog'}
// select properties and options to test
var propsToTest =
{path: {regExpMatch: true, regExpReverse: true},
breed: {matchIfPObjPropMissing: true}};
// create the filter function
var filter = fos.makeFilterFn(propsToTest);
// filter
filter(request, pets);
// [ { name: 'growler'...},{name: 'duchy'...} ]
});
var request = {path: '/pets?role=guarddog', breed: 'chihuahua'}
// [ { name: 'growler'...} ]matchIfBothPropMissing
Property on the [options](#options) object that if equal to true, filter and matches functions will return truefor the given property's match test if the property being tested does not exist on BOTH pObj and tObj.
- valid values:
true,false - default:
false
If matchIfTObjMissing &/or matchIfPObjMissing is set to true, then the match will still return true if either the tObj or pObj property is missing, respectively, even if both are not missing.
Example:
it('should return true if properties missing in both pObj & tObj',
function() {
var options = {
matchIfBothPropMissing:true,
// matchIfTObjPropMissing: false // default is false
// matchIfPObjPropMissing: false // default is false
};
var props = ["prop1",'prop2.cat.tail'];
var pObj = {"prop1":"abc","prop2":{"cat":{"nose":"purple"}}};
var tObj = {"prop1":"abc","prop2":{"cat":{"nose":"brown"}}};
var f = fos.makeMatchFn(props,options);
f(pObj, tObj).should.equal(true);
});
it('should return false if property exists in either pObj & tObj' +
'and matchIf_ObjPropMissing is false', function() {
var options = {
matchIfBothPropMissing:true,
// matchIfTObjPropMissing: false // default is false
// matchIfPObjPropMissing: false // default is false
};
var props = ["prop1",'prop2.cat.tail'];
var pObj = {"prop1":"abc","prop2":{"cat":{"tail":"purple"}}};
var tObj = {"prop1":"abc","prop2":{"cat":{"nose":"brown"}}};
var f = fos.makeMatchFn(props,options);
f(pObj, tObj).should.equal(false);
pObj = {"prop1":"abc","prop2":{"cat":{"nose":"purple"}}};
tObj = {"prop1":"abc","prop2":{"cat":{"tail":"brown"}}};
f(pObj, tObj).should.equal(false);
});
it('should return true if property exists in either pObj & tObj' +
'and matchIf_ObjPropMissing is true', function() {
var options = {
matchIfBothPropMissing:true,
matchIfTObjPropMissing: true,
matchIfPObjPropMissing: true
};
var props = ["prop1",'prop2.cat.tail'];
var pObj = {"prop1":"abc","prop2":{"cat":{"tail":"purple"}}};
var tObj = {"prop1":"abc","prop2":{"cat":{"nose":"brown"}}};
var f = fos.makeMatchFn(props,options);
f(pObj, tObj).should.equal(true);
pObj = {"prop1":"abc","prop2":{"cat":{"nose":"purple"}}};
tObj = {"prop1":"abc","prop2":{"cat":{"tail":"brown"}}};
f(pObj, tObj).should.equal(true);
});variables (variablesInPObj, variablesInTObj)
variablesInPObj and variablesInTObj are properties on the [options](#options) object that if equal to true, replaces strings that are recognized as variable names in pObj &/or tObj property values respectively with their respective variable values from [variables](#variables). The varible names on the property values is matched based on the [variablesStartStr](#variablesStartStr) and [variablesEndStr](#variablesStartStr).
- valid values:
true,false - default:
false
Example:
// match if fido has a grey tail and paws regardless if grey or gray
var fos = require('filter-objects');
var fido ={
paws: {color: 'grey', count: 3},
tail: {color: 'gray', count: 1},
body: {color: 'black'},
housetrained: true};
var options =
{regExpMatch: true,
variablesInPObj:true,
variablesStartStr:"+",
variablesEndStr: ":",
variables: {grayColor: /gr[a,e]y/i}
};
// variable name is identified between variablesStartStr(~) and variablesEndStr(#)
// and replaced with that name from variables (grayColor => /gr[a,e]y/)
var pObj = {paws:{color: '+grayColor:'}, tail:{color: '+grayColor:'}};
var propsToTest = ['paws.color','tail.color'];
var matchFn = fos.makeMatchFn(propsToTest, options);
matchFn(pObj, fido) // true;
// Or substitue variables in both pObj and tObj
var options = {variables: {youngDog: "puppy", littleCuteUn: "puppy"}};
var props =
{"prop1":
{"variablesInTObj":true,
"variablesInPObj":true,
"variablesStartStr":"/:"}};
var pObj = {"prop1":"/:littleCuteUn"};
var tObj = {"prop1":"/:youngDog"};
var f = fos.makeMatchFn(props, options);
f(pObj, tObj); //truevariables
Property on the [options](#options) object that defines the variable names and values.
See [variablesInPObj](#variablesInPObj) for an example.
variablesStartStr
Property on the [options](#options) object that defines a string which, if [variablesInPObj](#variablesInPObj) === true or [variablesInTObj](#variablesInTObj) === true, determines the starting position of a variable name string in a pObj property value that will be replaced with the variable value string of the respective variable name obtained from [variables](#variables).
See [variablesInPObj](#variablesInPObj) for an example.
variablesEndStr
Property on the [options](#options) object that defines a string which, if [variablesInPObj](#variablesInPObj) === true or [variablesInTObj](#variablesInTObj) === true, determines the ending position of a variable name string in a pObj property value that will be replaced with the variable value string of the respective variable name obtained from [variables](#variables).
See [variables](#variables) for examples.
doNotCheckInherited
Property on the [options](#options) object that if true will cause matches and filter functions to not include inherited properties for matching of pattern &/or target objects.
- valid values:
true,false - default:
false
Example:
var props = ["prop1"];
var o = {"prop1":"abc"};
var pObj = Object.create(o);
var tObj = {"prop1":"abc"};
// doNotCheckInherited is set to true at global level with this call so
// all inherited properties will be ignored (considered missing)
// on both tObj and pObj.
// doNotCheckInherited could also be set at the property level on
// either or both pObj and tObj like all options.
var f = fos.makeMatchFn(props, {doNotCheckInherited: true});
f(pObj, tObj); // false
// inherited properties are considered missing if doNotCheckInherited
var props = ["prop1"];
var o = {"prop1":"abc"};
var pObj = Object.create(o);
var tObj = {"prop1":"abc"};
var options = {doNotCheckInherited: true, matchIfPObjPropMissing: true}
var f = fos.makeMatchFn(props, options);
f(pObj, tObj); // true propMatchFn
Property on the [options](#options) object that defines a function to replace the match function between pObj and tObj properties.
- default:
null
Function is called with 3 parameters for each property being tested:
pObjProp- an object-literal with these 2 properties:value: the value of the [pObj](#pObj) property valueexists:trueorfalsedepending on whether the property exists onpObj
tObjProp- an object-literal with these 2 properties:value: the value of the [tObj](#tObj) property valueexists:trueorfalsedepending on whether the property exists ontObj
Example:
// find pets with 3 or more paws
var fos = require('filter-objects');
var pets = [
{ name: 'fido',
paws: {color: 'gray', count: 3}},
{ name: 'rover',
paws: {color: 'white', count: 4}},
{ name: 'slither',
paws: {count: 0}},
];
var pObj = {paws:{count: 3}};
// propMatchFn is called for each property with the
// pattern object property value and the target object property value
var matchFn = function(pObjProp, tObjProp) {
var hasAtLeast3Paws = tObjProp.exists === true &&
pObjProp.exists === true &&
tObjProp.value >= pObjProp.value;
return hasAtLeast3Paws;
};
var propsToTest = {'paws.count': {propMatchFn: matchFn}};
var filter = fos.makeFilterFn(propsToTest);
filter(pObj, pets);
//matchedPets = {name: 'fido'..., name:'rover'...}; setOptionsOnProps(propsToTest, options)
Helper function to modify the propsToTest object setting options on each property. setOptionsOnProps is called by makeFilterFn and makeMatchFn so setOptionsOnProps does not need to be called prior to those. setOptionsOnProps is exposed to see the options set for each property. As noted in makeFilterFn and makeMatchFn, options precedence is (1) propsToTest options values if set (2) options as included here as a parameter, otherwise (3) options default values.
Arguments
propsToTest- options: Object with any of
optionsproperties.
Examples
var propsToTest = [
'method',
'query.filter',
{name:'query.limit', regExpMatch: false}];
var options = {regExpMatch: true};
var updatedProps = fos.setOptionsOnProps(propsToTest, options);
console.log(updatedProps);
/*
[ { name: 'method',
regExpReverse: false,
regExpIgnoreCase: false,
regExpAnchorStart: false,
regExpAnchorEnd: false,
matchIfPObjPropMissing: false,
matchIfTObjPropMissing: false,
matchIfBothPropMissing: false,
variables: {},
variablesInPObj: false,
variablesInTObj: false,
variablesStartStr: '~',
variablesEndStr: null,
propMatchFn: null,
regExpMatch: true },
{ name: 'query.filter',
regExpReverse: false,
regExpIgnoreCase: false,
regExpAnchorStart: false,
regExpAnchorEnd: false,
matchIfPObjPropMissing: false,
matchIfTObjPropMissing: false,
matchIfBothPropMissing: false,
variables: {},
variablesInPObj: false,
variablesInTObj: false,
variablesStartStr: '~',
variablesEndStr: null,
propMatchFn: null,
regExpMatch: true },
{ name: 'query.limit',
regExpMatch: false,
regExpReverse: false,
regExpIgnoreCase: false,
regExpAnchorStart: false,
regExpAnchorEnd: false,
matchIfPObjPropMissing: false,
matchIfTObjPropMissing: false,
matchIfBothPropMissing: false,
variables: {},
variablesInPObj: false,
variablesInTObj: false,
variablesStartStr: '~',
variablesEndStr: null,
propMatchFn: null } ]
*/
// Above can just be informational if needed or can be fed into makeFilterFn or makeMatchFn
var filter = makeFilterFn(updatedProps);
// which would have the same result as this:
var filter = makeFilterFn(propsToTest, options);setNestedPropOptions(propsToTest, propOptions)
Helper function to modify propsToTest so that options for each property cascade from higher level properties in propOptions to lower level properties. propsToTest can then be used as input to makeFilterFn or makeMatchFn. (Note that only options are cascaded. Which properties is not cascaded. See propsToTest).
Arguments
propsToTest- propOptions: A literal object with propNames as keys and
optionsas values.
Examples
var propsToTest = [
'method',
'query',
'query.filter',
{name:'query.limit', regExpMatch: false},
'query.filter.sort'];
var propOptions = {
'query': {regExpMatch: true}, // cascade this option to all 'query.x' where isn't set on lower levels
'query.limit': {variablesInTObj: true}
};
var updatedProps = fos.setNestedPropOptions(propsToTest, propOptions);
console.log(updatedProps);
/*
{ method: {},
query: { regExpMatch: true },
'query.filter': { regExpMatch: true },
'query.limit': { regExpMatch: false, variablesInTObj: true },
'query.filter.sort': { regExpMatch: true } }
*/
var options = {regExpReverse: true};
var filter = makeFilterFn(propsToTest, options);
// filter will test properties in propsToTest with those options
// and defaulting to regExpReverse to true across all of them
// (so for all props in propsToTest because it isn't set in any of the properties)
// Any option that isn't set in propsToTest or options will be set
// according to global options default - see options section.
...Performance
An overall summary of benchmark performance tests can be found here. Details can be found in the performance/results folder of the perf-results branch.
Some general observations from the performance benchmark tests:
- Always use
makeFilterFnto create your filter if possible rather than callingfilterdirectly. RunningmatcheswithoutmakeMatchFn(on whichfilteris based) can run about 10 times slower. - 95% of response times for
filterare less than .10 μs and 10 μs per property (μs = microsecond = .001 millisecond) on a fresh build smallest available aws Linux server. This means that if filtering on one property, each filtered object responded within .10 μs and 10 μs 95% of the time. If filtering on 10 properties, it would have responded within 1 μs and 100 μs per object 95% of the time (10 x). - Depth of properties matters. This is true for both hard-coded array filters (using javascript Array.prototype.filter directly) or using filter-objects. Filtering on bojects with properties going from 1 deep to 4 deep increased the result time anywhere from 0 to almost 6 times with most response times increasing 2-3 times (again, looking at 95th percentile).
- Still call Array.prototype.filter directly if you can and if performance is paramount. filter-objects adds performance overhead to calling Array.prototype.filter directly - as would be expected. The 95th percentile response time increased from a range of .07-1.24 μs per filter property for calling Array.prototype.filter directly to a range of 1.38-4.33 μs for the same filters with filter-objects (again - using makeFilterFn).