Match a javascript object against a json filter. The filter syntax is like a mongodb query language. There is a support for creation of the user defined filter operators.
Comparison operators
- $empty Check for false
- $exists The field does not exist
- $eq Equal to
- $gt Greater than
- $gte Greater than or equal to
- $lt Lesser than
- $lte Lesser than or equal to
- $ne Not equal to
- $regex Match to regular expression
Other context operators
- $ceil The next highest integer
- $floor The next lowest integer
- $round Round to integer
- $ceilRH The next highest integer. Right handed
- $floorRH The next lowest integer. Right handed
- $roundRH Round to integer. Right handed
- $mod Remainder of the division (modulo)
- $sub Difference
- $val The document selector value
Array operators
- $all All values are in the given array
- $in The value is in the given array
- $nin The value is not in the given array
Logical operators
The filter can be defined as JSON string:
var filterData = '{"src": "io"}';
or as a plain javascript object:
var filterData = {
src: "io"
};
The factory JsonFilter.create must be called to create filter instance. Do not use constructors. They are for internal purposes.
var JsonFilter = require("jsfilter").JsonFilter;
var filter = JsonFilter.create(filterData);
Match the document against the filter instance:
if (filter.match(document)) {
// ...
}
The filter definition object is a plain javascript object. It is used to create filter instance by the factory call JsonFilter.create. It can be defined also as a valid JSON string.
The keys in the filter object are dot notation selectors for data in the input document. The dots in the key names must be escaped with symbol ''. The square brackets notation is supported too but it is less efficient and internally converted to escaped dot notation. So prefer to use dot notation. The values of the filter object are filter operators that will be applied to document data selected by the corresponding selector. Filter operators are JSON objects and its names begin with symbol '$'.
filter example:
{
"src": "io",
"user.loginsCount": {"$gt": 0},
"user[.ref.type]": "bbbb",
"user.ref\.type": "uuuu"
}
The filter in the example allows only those documents that satisfy all following requirements:
- field src is equal to io
- field loginsCount of the object user is greater than 0
- field .ref.type of user is equal to "bbbb"
- field ref.type of user is equal to "uuuu"
document example:
{
src: "io",
user: {
loginsCount: 100500,
".ref.type": "bbbb",
"ref.type": "uuuu"
}
}
There are following exceptions in the package:
JFP_Error
The base package exception is inherited from Error. All other exceptions in the package inherit this one. In corrects standard fields message, name and stack.
No additional fields are set.
JFP_CreateOperatorError
Filter operator creation error.
Additional fields:
- data - the data that was used to construct the operator
JFP_ParseOperandError
Operator's operands parser error. Checks whether the operand defined in the filter is correct.
Additional fields:
- operator - the operator instance that owns the given operand
- operand - operand's definition
JFP_ParseError
Filter structure parse error.
Additional fields:
- key - the filter object key that holds the erroneous data
- operand - the erroneous data
JFP_MatchError
Filter match error.
Additional fields:
- matchOperator - the failed filter operator
- matchOperand - the failed operator's operand
- matchContext - the failed operator's context
To create your own filter operator your have to:
-
Create javascript object with parameters of the operator to be created. The fields of this object are:
- name - Operator's name. Must begin with '$' symbol.
- operandsType - Type of the expected operand:
- array - array
- regex - regular expression
- operator - other operator
- context - document context selector
- value - all except the above types
- operandsCountMin - minimum array elements count for array type
- operandsCountMax - maximum array elements count for array type
- match - the string with matching function body
The fields name, operandsType and match are required.
Parameter match is used for javascript Function constructor as follows:
new Function("context", "operand", "document", "operators", data.match);
where:
- context - document context for the operator
- operand - operand
- document - hole document
- operators - object with all operators by its names (example: operators.$eq)
Consider an example:
{ "user.age": {"$gt": 12} }
Here for operator $gt the context is "user.age" and the operand is 12.
-
Create operator instance with factory JsonFilterOperator.create
var data = { name: "$gt", operandsType: "value", match: "return context > operand" }; var operator = JsonFilterOperator.create(data);
-
Create an object to hold your operators or get default one
Create new empty object (built-in operators will be unavailable)
var defaults = {};
or create new object with a set of built-in operators
var defaults = JsonFilterOperator.createDefaults();
or get static system defaults
var defaults = JsonFilter.getDefaults();
-
Add your operator to this object
defaults[operator.name] = operator
-
Create your filters with custom defaults
JsonFilter.create({smth: {$gt: 3}}, defaults);
If you add your operator to system defaults (got with JsonFilter.getDefaults) than the second argument can be omitted
JsonFilter.create({smth: {$gt: 3}});
$empty
Checks whether the context is an empty value
{
"user.loginsCount": {"$empty": true}
}
The next values are considered to be empty:
- 0
- null
- undefined
- ''
- false
- '0'
- []
- {}
$exists
Checks whether the field exists in the document (check for undefined)
{
"user.registrationTime": {"$exists": false}
}
$eq
Checks for non-strict equality. Arrays and objects are compared recursively.
{
"user.loginsCount": {"$eq": 5},
"user.rates": {"$eq": {"2x2": 100, "5x5": 200}}
"user.jobs": {"$eq": ["newbie", "farmer"]}
}
If you compare with primitive types than the operator expression can be simplified. You can write just the value instead of operator construction. This form will be converted to full operator form internally.
{
"user.loginsCount": 5
}
$ne
Checks for non-strict equality (not equal to). Arrays and objects are compared recursively.
{
"user.loginsCount": {"$ne": 5}
}
$gt
Greater than
{
"user.loginsCount": {"$gt": 5}
}
$gte
Greater than or equal to
{
"user.loginsCount": {"$gte": 5}
}
$lt
Less than
{
"user.loginsCount": {"$lt": 5}
}
$lte
Less than or equal to
{
"user.loginsCount": {"$lte": 5}
}
$regex
Checks for match with regular expression
{
"user.class": {"$regex": "^fighter"},
"user.clan.duties": {"$regex": "/newbie/i"}
}
If you do not need to use the regular expression flags (case insensitivity, for example), than the bound symbols '/' can be omitted.
$ceil
The next highest integer
{
"user.average": {"$ceil": 4}
}
$floor
The next lowest integer
{
"user.average": {"$floor": 3}
}
$round
Round to integer
{
"user.average": {"$round": 3}
}
$ceilRH
The next highest integer. This is a right handed operator that is its operand is taken from the right part of the operator expression.
{
"tm": {
"$gt": {"$ceilRH": "user.avg"}
}
}
The simplified form with an implicit $eq
"tm": {"$ceilRH": "user.avg"}
$floorRH
The next lowest integer. This is a right handed operator that is its operand is taken from the right part of the operator expression.
{
"tm": {
"$gt": {"$floorRH": "user.avg"}
}
}
The simplified form with an implicit $eq
"tm": {"$floorRH": "user.avg"}
$roundRH
Round to integer. This is a right handed operator that is its operand is taken from the right part of the operator expression.
{
"tm": {
"$gt": {"$roundRH": "user.avg"}
}
}
The simplified form with an implicit $eq
{
"tm": {"$roundRH": "user.avg"}
}
$mod
Remainder of the integer division (modulo). The operand must be an array of two numbers: divisor and expected remainder.
{
"user.purchases": {"$mod": [5, 0]}
}
$sub
Difference between two context values
{
"ts": {
"$sub": {
"user.lastLoginTime": {"$lt": 300}
}
}
}
$val
Get the context value. This is a right handed operator that is its operand is taken from the right part of the operator expression.
{
"ts": {
"$eq": {"$val": "user.lastLoginTime"}
}
}
The simplified form with an implicit $eq
{
"ts": {"$val": "user.lastLoginTime"}
}
$all
All elements of the array document context value must be members of the given operand array. If the document context value is not an array than the operator is equivalent to $in.
{
"user.roles": {
"$all": ["cleaner", "washer", "cook"]
}
}
$in
The document context value must be a member of the given operand array. If the document context value is an array than the operator checks that at least one of its elements must be a member of the given operand array.
{
"user.role": {
"$in": ["cleaner", "washer", "cook"]
}
}
The simplified form with an implicit $in
{
"user.role": ["cleaner", "washer", "cook"]
}
$nin
The document context value must not be a member of the given operand array. If the document context value is an array than the operator checks that no one of its elements is not a member of the given operand array.
{
"user.role": {
"$nin": ["cleaner", "washer", "cook"]
}
}
$and
Logical AND to combine independent conditions. The document must satisfy all the combined conditions.
{
"$and": [
{"user.sex": "male"},
{"user.class": "warrior"}
]
}
The simplified form with an implicit $and
{
"user.sex": "male",
"user.class": "warrior"
}
$or
Logical OR to combine independent conditions. The document must satisfy at least one of the combined conditions.
{
"$or": [
{"user.sex": "male"},
{"user.class": "warrior"}
]
}
The simplified form with an implicit $or
[
{"user.sex": "male"},
{"user.class": "warrior"}
]
$nor
Logical NOR to combine independent conditions. The document must not satisfy any of the combined conditions.
{
"$nor": [
{"user.sex": "male"},
{"user.class": "warrior"},
{"user.age": {"$lt": 12}}
]
}
$not
Logical NOT to negate the result of the previous logical operation. The operator context is passed to the next operator without changes.
"user.age": {
$not: {$lt: 12}
}
$ctxAnd
Logical AND to combine operations with shared context. The document must satisfy all the combined conditions.
{
"user.age": {
"$ctxAnd": [
{"$lt": 45},
{"$gt": 12}
]
}
}
The simplified form with an implicit $ctxAnd
{
"user.age": {
"$lt": 45,
"$gt": 12
}
}
$ctxOr
Logical OR to combine operations with shared context. The document must satisfy at least one of the combined conditions.
{
"user.role": {
"$ctxOr": [
{"$regex": "newbie"},
{"$regex": "baboon"}
]
}
}
The simplified form with an implicit $ctxOr
{
"user.role": [
{"$regex": "newbie"},
{"$regex": "baboon"}
]
}