Installation: npm install sift
, or yarn add sift
Sift is a tiny library for using MongoDB queries in Javascript
For extended documentation, checkout http://docs.mongodb.org/manual/reference/operator/query/
Features:
- Supported operators: \$in, \$nin, \$exists, \$gte, \$gt, \$lte, \$lt, \$eq, \$ne, \$mod, \$all, \$and, \$or, \$nor, \$not, \$size, \$type, \$regex, \$where, \$elemMatch
- Regexp searches
- Supports node.js, and web
- Custom Operations
- Tree-shaking (omitting functionality from web app bundles)
Examples
import sift from "sift";
//intersecting arrays
const result1 = ["hello", "sifted", "array!"].filter(
sift({ $in: ["hello", "world"] })
); //['hello']
//regexp filter
const result2 = ["craig", "john", "jake"].filter(sift(/^j/)); //['john','jake']
// function filter
const testFilter = sift({
//you can also filter against functions
name: function(value) {
return value.length == 5;
}
});
const result3 = [
{
name: "craig"
},
{
name: "john"
},
{
name: "jake"
}
].filter(testFilter); // filtered: [{ name: 'craig' }]
//you can test *single values* against your custom sifter
testFilter({ name: "sarah" }); //true
testFilter({ name: "tim" }); //false
API
sift(query: MongoQuery, options?: Options): Function
Creates a filter with all of the built-in MongoDB query operations.
-
query
- the filter to use against the target array -
options
-
operations
- custom operations -
compare
- compares difference between two values
-
Example:
import sift from "sift";
const test = sift({ $gt: 5 }));
console.log(test(6)); // true
console.log(test(4)); // false
[3, 4, 5, 6, 7].filter(sift({ $exists: true })); // [6, 7]
createQueryTester(query: Query, options?: Options): Function
Creates a filter function without built-in MongoDB query operations. This is useful if you're looking to omit certain operations from application bundles. See Omitting built-in operations for more info.
import { createQueryTester, $eq, $in } from "sift";
const filter = createQueryTester({ $eq: 5 }, { operations: { $eq, $in } });
createEqualsOperation(params: any, ownerQuery: Query, options: Options): Operation
Used for custom operations.
import { createQueryTester, createEqualsOperation, $eq, $in } from "sift";
const filter = createQueryTester(
{ $mod: 5 },
{
operations: {
$something(mod, ownerQuery, options) {
return createEqualsOperation(
value => value % mod === 0,
ownerQuery,
options
);
}
}
}
);
filter(10); // true
filter(11); // false
Supported Operators
See MongoDB's advanced queries for more info.
\$in
array value must be \$in the given query:
Intersecting two arrays:
//filtered: ['Brazil']
["Brazil", "Haiti", "Peru", "Chile"].filter(
sift({ $in: ["Costa Rica", "Brazil"] })
);
Here's another example. This acts more like the \$or operator:
[{ name: "Craig", location: "Brazil" }].filter(
sift({ location: { $in: ["Costa Rica", "Brazil"] } })
);
\$nin
Opposite of \$in:
//filtered: ['Haiti','Peru','Chile']
["Brazil", "Haiti", "Peru", "Chile"].filter(
sift({ $nin: ["Costa Rica", "Brazil"] })
);
\$exists
Checks if whether a value exists:
//filtered: ['Craig','Tim']
sift({ $exists: true })(["Craig", null, "Tim"]);
You can also filter out values that don't exist
//filtered: [{ name: "Tim" }]
[{ name: "Craig", city: "Minneapolis" }, { name: "Tim" }].filter(
sift({ city: { $exists: false } })
);
\$gte
Checks if a number is >= value:
//filtered: [2, 3]
[0, 1, 2, 3].filter(sift({ $gte: 2 }));
\$gt
Checks if a number is > value:
//filtered: [3]
[0, 1, 2, 3].filter(sift({ $gt: 2 }));
\$lte
Checks if a number is <= value.
//filtered: [0, 1, 2]
[0, 1, 2, 3].filter(sift({ $lte: 2 }));
\$lt
Checks if number is < value.
//filtered: [0, 1]
[0, 1, 2, 3].filter(sift({ $lt: 2 }));
\$eq
Checks if query === value
. Note that \$eq can be omitted. For \$eq, and \$ne
//filtered: [{ state: 'MN' }]
[{ state: "MN" }, { state: "CA" }, { state: "WI" }].filter(
sift({ state: { $eq: "MN" } })
);
Or:
//filtered: [{ state: 'MN' }]
[{ state: "MN" }, { state: "CA" }, { state: "WI" }].filter(
sift({ state: "MN" })
);
\$ne
Checks if query !== value
.
//filtered: [{ state: 'CA' }, { state: 'WI'}]
[{ state: "MN" }, { state: "CA" }, { state: "WI" }].filter(
sift({ state: { $ne: "MN" } })
);
\$mod
Modulus:
//filtered: [300, 600]
[100, 200, 300, 400, 500, 600].filter(sift({ $mod: [3, 0] }));
\$all
values must match everything in array:
//filtered: [ { tags: ['books','programming','travel' ]} ]
[
{ tags: ["books", "programming", "travel"] },
{ tags: ["travel", "cooking"] }
].filter(sift({ tags: { $all: ["books", "programming"] } }));
\$and
ability to use an array of expressions. All expressions must test true.
//filtered: [ { name: 'Craig', state: 'MN' }]
[
{ name: "Craig", state: "MN" },
{ name: "Tim", state: "MN" },
{ name: "Joe", state: "CA" }
].filter(sift({ $and: [{ name: "Craig" }, { state: "MN" }] }));
\$or
OR array of expressions.
//filtered: [ { name: 'Craig', state: 'MN' }, { name: 'Tim', state: 'MN' }]
[
{ name: "Craig", state: "MN" },
{ name: "Tim", state: "MN" },
{ name: "Joe", state: "CA" }
].filter(sift({ $or: [{ name: "Craig" }, { state: "MN" }] }));
\$nor
opposite of or:
//filtered: [{ name: 'Joe', state: 'CA' }]
[
{ name: "Craig", state: "MN" },
{ name: "Tim", state: "MN" },
{ name: "Joe", state: "CA" }
].filter(sift({ $nor: [{ name: "Craig" }, { state: "MN" }] }));
\$size
Matches an array - must match given size:
//filtered: ['food','cooking']
[{ tags: ["food", "cooking"] }, { tags: ["traveling"] }].filter(
sift({ tags: { $size: 2 } })
);
\$type
Matches a values based on the type
[new Date(), 4342, "hello world"].filter(sift({ $type: Date })); //returns single date
[new Date(), 4342, "hello world"].filter(sift({ $type: String })); //returns ['hello world']
\$regex
Matches values based on the given regular expression
["frank", "fred", "sam", "frost"].filter(
sift({ $regex: /^f/i, $nin: ["frank"] })
); // ["fred", "frost"]
["frank", "fred", "sam", "frost"].filter(
sift({ $regex: "^f", $options: "i", $nin: ["frank"] })
); // ["fred", "frost"]
\$where
Matches based on some javascript comparison
[{ name: "frank" }, { name: "joe" }].filter(
sift({ $where: "this.name === 'frank'" })
); // ["frank"]
[{ name: "frank" }, { name: "joe" }].filter(
sift({
$where: function() {
return this.name === "frank";
}
})
); // ["frank"]
\$elemMatch
Matches elements of array
var bills = [
{
month: "july",
casts: [
{
id: 1,
value: 200
},
{
id: 2,
value: 1000
}
]
},
{
month: "august",
casts: [
{
id: 3,
value: 1000
},
{
id: 4,
value: 4000
}
]
}
];
var result = bills.filter(
sift({
casts: {
$elemMatch: {
value: { $gt: 1000 }
}
}
})
); // {month:'august', casts:[{id:3, value: 1000},{id: 4, value: 4000}]}
\$not
Not expression:
["craig", "tim", "jake"].filter(sift({ $not: { $in: ["craig", "tim"] } })); //['jake']
["craig", "tim", "jake"].filter(sift({ $not: { $size: 5 } })); //['tim','jake']
Date comparison
Mongodb allows you to do date comparisons like so:
db.collection.find({ createdAt: { $gte: "2018-03-22T06:00:00Z" } });
In Sift, you'll need to specify a Date object:
collection.find(
sift({ createdAt: { $gte: new Date("2018-03-22T06:00:00Z") } })
);
Custom behavior
Sift works like MongoDB out of the box, but you're also able to modify the behavior to suite your needs.
Custom operations
You can register your own custom operations. Here's an example:
import sift, { createEqualsOperation } from "sift";
var filter = sift(
{
$customMod: 2
},
{
operations: {
$customMod(params, ownerQuery, options) {
return createEqualsOperation(
value => value % params !== 0,
ownerQuery,
options
);
}
}
}
);
[1, 2, 3, 4, 5].filter(filter); // 1, 3, 5
Omitting built-in operations
You can create a filter function that omits the built-in operations like so:
import { createQueryTester, $in, $all, $nin, $lt } from "sift";
const test = createQueryTester(
{
$eq: 10
},
{ operations: { $in, $all, $nin, $lt } }
);
[1, 2, 3, 4, 10].filter(test);
For bundlers like Webpack
and Rollup
, operations that aren't used are omitted from application bundles via tree-shaking.