-
Notifications
You must be signed in to change notification settings - Fork 4
List
OGX.JS provides a SuperArray named List which extends the natural Javascript Array by adding methods without tempering any of the native ones. However, its power is found using array of objects, as it supports filtering, sorting and grouping by properties. It also converts properly to JSON using JSON.stringify.
If you want to use this single component only, scroll to the bottom of the page.
let array = new OGX.List(1,2,3); //Standard array, doesn't offer much improvements over Array
let array = new OGX.List([1,2,3]); //You can also pass as array but it will give the same result (array ignored)
let array = new OGX.List({id:1},{id:2},{id:3}); //Array of objects, now we're talking!
let array = new OGX.List([{id:1},{id:2},{id:3}]); //Same result as previous line, array ignored
Keep in mind this super array is designed primarily to handle lists of objects. If you wish to manipulate multi dimensional arrays such as
[[1,2], [3,4]]
without worrying about data transformation, it is recommended to use a standard array.
For the rest of the documentation, please consider the following super array
let array = new OGX.List(
{id:1, name:'Chad', age:20, gender:'male', registered:'2017-01-01', salary:10000},
{id:2, name:'Sarah', age:30, gender:'female', registered:'2017-01-02', salary:25000},
{id:3, name:'Tyrone', age:25, gender:'male', registered:'2017-01-03', salary:35000},
{id:4, name:'Stacy', age:40, gender:'female', registered:'2017-01-04', salary:60000}
);
array.insert(_*_, _INDEX_); //Insert item at position
array.delete(_INDEX_); //Delete item at position
array.findDelete(_PROPERTY_, _VALUE_, _INT_LIMIT_); //Delete item(s) matching the property/value pair, returns the deleted item(s)
array.findReplace(_PROPERTY_, _VALUE_, _OBJECT_, _LIMIT_); //Find and replace all matching elements by a new element, returns an array of found elements before they were replaced
array.findUpdate(_PROPERTY_, _VALUE_, _OBJECT_, _BOOL_STRICT_, _LIMIT_); //Find and update partially or totally an element given another object. If _BOOL_STRICT_ is set true, only the existing properties are updated, none are created
array.findIndex(_PROPERTY_, _VALUE_); //Find index of the first element matching the property/value pair
array.find(_PROPERTY_, _VALUE_, _INT_LIMIT_); //Returns a OGX.list with all matched items(s)
array.get(_QUERY_); //Returns a OGX.List with all matched items(s) based on a query object
array.update(_QUERY_, _OBJECT_, _BOOL_STRICT_, _LIMIT_) //Update items found with search query
array.unset(_QUERY_); //Find and delete items matching a query
array.deleteProperty(_PROPERTY_); //Delete a property for every document, returns number of altered documents
array.unique(_PROPERTY_, _MAP_); //Find unique values and remap (optional)
array.last(); //Returns the last item of the list
array.swap(_INDEX0_, _INDEX1_); //Swaps 2 items
array.clear(); //Remove all data and filters and indexes
All find methods return a single object if the limit is set to 1. Otherwise, they return a OGX.List with the matched document(s).
Note that find, findDelete and findIndex support regular expressions. The following line look for objects with the property name starting with the letter s and delete them and will stop after it has deleted 2 matches
array.findDelete('name', /^s/gi, 2);
To find the index of an object
array.findIndex('name', 'Sarah'); //Return an object of format {index:_INT_}
To find a maximum of 5 persons with name starting with a letter S
array.find('name', /^s/gi, 5); //Returns new OGX.List with match item(s)
To change the age to 50, for all males, do
array.findUpdate('gender', 'male', {age:50});
To change the salary and the age of 'Chad', do
array.findUpdate('name', 'Chad', {age:16, salary:1000}, false, 1);
array.order(_PROPERTY_, _WAY_);
For instance, to sort by name descending
array.order('name', -1);
OGX.List provides filtering operations inspired by mongodb. In order to filter the list, you must add filters to the super array then filter it. You can also remove filters.
array.addFilter(_PROPERTY_, _MODE_, _VALUE_); //Add a filter
array.removeFilter(_PROPERTY_); //Remove a filter
array.getFilters(); //Returns a filter object
array.setFilters(_FILTERS_); //Sets the filters
array.resetFilters(); //Remove all filters
array.filter(); //Filters the list and returns a new OGX.List
array.setFilteringMode(_STRING_); //Either "and" or "or", defaults to "and"
In the following example, we filter our (sorted now) list by only keeping female(s) older than 25 years old
array.addFilter('gender', 'eq', 'female');
array.addFilter('age', 'gt', 25);
let filtered_list = array.filter();
Note that the returned array is also a super array.
You can also import/exports filters between OGX.List instances, such as
let filters = array.getFilters();
some_other_array.setFilters(filters);
You can also take a shortcut to adding filters and use the get method, see querying
Here is the list of available modes for filtering operations
'eq' //Equal to
'eqjson' //For deep objects, JSON comparison, equal to
'neq' //Not equal to
'in' //Contains
'nin' //Doesn't contain
'lt' //Lesser than
'lte' //Lesser or equal to
'gt' //Greater than
'gte' //Greater or equal to
'btw' //Between, expects value to be array [_from_, _to_]
'substr' //Substring mode, equal to, expects value to be array [_from_, _to_, _niddle_]
'regex' //Regex match
'exist' //if the property exists
OGX.JS also supports filtering over dates and date-time objects (as string). For instance, to filter all people registered between the 2017-01-01 and 2017-01-04 (not inclusive), do
array.addFilter('registered', 'btw', ['2017-01-01', '2017-01-04']);
Or to obtain people registered after the 1st of January, do
array.addFilter('registered', 'gt', '2017-01-01');
To obtain people whose first name starts by the letter S, you can do
array.addFilter('name', 'substr', [0, 1, 'S']);
You can do the equivalent using the regex operator
array.addFilter('name', 'regex', /^s/gi);
All of these filters produce the same result
array.addFilter('gender', 'in', 'fe');
array.addFilter('gender', 'eq', 'female');
array.addFilter('gender', 'neq', 'male');
array.addFilter('gender', 'regex', /^fe/gi);
array.addFilter('gender', 'substr', [0, 2, 'fe']);
Note that filtering over strings is case insensitive. To filter case sensitive, use the regex operator. Also note that the 'in' and 'nin' operators also accept array to array comparison, and in this case the filtering is case sensitive and type sensitive. For the following example, consider that the elements of our list have tags such as ['red', 'blue', 'yellow', 'black']. To filter all elements that have BOTH red and blue tags, do
array.addFilter('tags', 'in', ['red', 'blue']);
By default, OGX.List filtering will only return the items that match all filters. If you wish to get the items that match at least 1 filter, you can set the filtering mode to "or".
array.setFilteringMode('or');
You can at anytime set it back to its default "and" mode
array.setFilteringMode('and');
OGX.List also offers the possibility to extend its filtering capabilities by using custom filtering functions. All custom filters must return true or false.
//custom filter receiving the value of the filtered property
function myCustomFilter(__val){
if(...){
return true;
}
return false;
}
//filtering with it
array.addFilter('some_property', myCustomFilter, null);
You can also query the list by using the get method, which is basically a shortcut to creating filters one by one, by using a single object, such as
let res = array.get({age:{gte:50, lte:78}, name:{in:'Chad'}});
being the exact same as
array.addFilter('age', 'gte', 50);
array.addFilter('age', 'lte', 78);
array.addFilter('name', 'in', 'Chad');
let res = array.filter();
And you can also add a sort object and a limit, such as
let res = array.get({age:{gte:50, lte:78}, name:{in:'Chad'}}, {age:-1}, 5);
Which equates to
array.addFilter('age', 'gte', 50);
array.addFilter('age', 'lte', 78);
array.addFilter('name', 'in', 'Chad');
let res = array.filter(5);
res.order('age', -1);
And you can also group your get result by passing a grouping such as
let res = array.get({age:{gte:50, lte:78}, name:{in:'Chad'}}, {age:-1}, ['age'], 5);
And also multiple levels of grouping
let res = array.get({age:{gte:50, lte:78}, name:{in:'Chad'}}, {age:-1}, [['age', 'salary], [null, 'numrange'], [null, [10000, '$', 'pre']]], 5);
For more information about grouping, keep scrolling.
You can also use the get function for deep path queries, such as
let res = array.get({"travel.start":{eq:"2018-10-10"}});
Note that since version
1.36.0
, you can omit theeq
and use a property/value pair instead
let res = array.get({"travel.start":"2018-10-10"});
You can update one of more records matching a property/value pair
array.findUpdate('name', 'Chad', {name:'Chael'});
You can also update one of more records using a search query.
array.update({age:{gte:50, lte:78}, name:{in:'Chad'}}, {name:'Chael'});
Since version
1.3.19
ofOGX.List
(version1.31.0
ofOGX.JS
), you can pass an update function, where you manually update the item, such as
array.update({}, (__item) => { ... your own update function });
To delete from the list given a query, use the
unset
method, which returns a new OGX.List containing the deleted objects, or a single object if the limit is set to 1
let obj = array.unset({name:{in:'Chad'}}, 1);
let list = array.unset({name:{in:'Chad'}}, 5);
You can delete a property from every item of the list, such as
array.deleteProperty('whatever');
You can retrieve unique values for a common property by doing
let values = array.unique('age', false);
//[20, 25, 30 ...]
Which returns a standard array of values. But you can also return these unique values as an OGX.List
let values = array.unique('age', true);
//[{age:20}, {age:25}, {age:30} ...]
and you can also specify a new name for the property
let values = array.unique('age', true, 'oldness');
//[{oldness:20}, {oldness:25}, {oldness:30} ...]
OGX.List can also return a grouped list by one property per group level
array.group(
_BY_, //Array or String, Common property to group by,
_MODE_, //Array or String, The grouping mode, substr, numrange, date or a numeric value in days to group by
_MODE_VALUE_ //Array or String, The value to use for the grouping mode
);
To group our array by age of groups of 10 years, do
array.group('age', 'numrange', 10);
numrange accepts up to 3 parameters, such as
array.group('salary', 'numrange', [_VALUE_, _UNIT_, _POSITION_]);
Which is very useful to group by number and display a unit (dollars, meters, etc.). To group by salary with groups of $10,000 and display it as $low-high such as $10000-$20000, do
array.group('salary', 'numrange', [10000, '$', 'pre']);
POSITION only accepts 'pre' or 'post'
To group by month (year-month)
array.group('registered', 'date', 'month');
The supported mode_values for a grouping by date are 'year', 'month' and 'week'. You can also pass a numeric value instead representing the numbers of days. To group by groups of 80 days, do
array.group('registered', 'date', 80);
To group by the first letter of the name
array.group('name', 'substr', [0, 1]);
Simple grouping (same age)
array.group('age');
You can also group a list with virtually unlimited sub groups or properties. Take note that all items must have all the grouping properties. MODE in this case can be an array of modes to be used per group, but if defined as a string, it will be common to all groups.
For instance, you can do a simple multi level grouping like this
array.group(['gender', 'salary']);
But in the case of the salary, we would want a different mode and mode_value to display the groups of salary properly, so we have to pass them both as array
let data = array.group(['gender', 'salary'], [null, 'numrange'], [null, [10000, '$', 'pre']]);
Now the list is going to be grouped first by gender (simple grouping) and then it's going to group its sub items by salary ranges of $10000
The final result is a JSON tree as deep as many groups that you pass to it, with the elements of the array at the deepest level of the grouping
//console.log(data);
{
"male":{
"$0-10000":[items],
"$10000-20000":[items],
...
},
"female":{
"$0-10000":[items],
"$10000-20000":[items],
...
}
}
Note that the array.group() method uses array.groupm() method if the first parameters is an array. As a safe net, always use array.group(). Also note that items are also held into an OGX.List.
If objects of your list all have a common index, and that you would like to speed up the process of fetching a single object using that index, you can cache your list. Once the cache has been turned on, any new object inserted to the list must have the index (property) to be added to the cache.
For instance, if all of your objects have the id property and you have a huge list, it could be slow to cycle the entire list to get a single object, moreover if that object is at the bottom of the list. And even worse so if, in your code, you constantly fetch objects one by one, by id.
list.cache('id');
Then to retrieve an object by id without cycling the list, in this case an object of
id equal to 100 limit 1
let object = list.read('id', 100, 1);
You can also use a combined index to index documents by id and color.
list.cache('size', 'color');
So later on, if you want to get all documents faster (if you only search by size and color), you can do
let arr = list.read({size:'XL', color:'blue'});
And apply a limit. If the limit is set to one, a single object is return instead of a list.
let arr = list.read({size:'XL', color:'blue'}, 5);
let obj = list.read({size:'XL', color:'blue'}, 1);
To remove an index
list.uncache('id');
To remove a combined index
list.uncache('size', 'color');
Keep in mind that the initial cost in performance associated with caching a huge list is high but this happens only once. Then, the subsequent reads will be then much faster than using get, unless you remove items of your list; In this case, all the indexes matching the item will have to be rebuilt but they will be rebuild in the next thread. If you need to force the indexing, you can do (not recommended).
list.rebuild();
OGX.JS also provides the ability to render a List via many different components, with more often than not, a single line of code.
Render List as OGX.DynamicList (editable list)
Render List as OGX.GroupedList (editable grouped list as nested list)
Render List as OGX.TreedList (editable grouped list as OGX.Tree or OGX.StackedTree)
If you are looking for a more complete solution to store and interact with a JSON database in the front end (and feed data to List), check out our mongodb inspired database for the front end MongOGX
OGX.List is now available as a separate component HERE.
- Welcome
- Changelog
- Structure
- Configuration
- Getting started
- CLI
- Poly
- Core
- Templating
- Routing
- Controllers
- Components
- Extra Components
- Helpers
- Styling
- Debugging