├── .babelrc ├── .editorconfig ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE.md ├── dist ├── datafield.min.js └── datafield.min.js.map ├── docs ├── datafield.png ├── index.html └── main.css ├── package.json ├── readme.md ├── rollup.config.js ├── src ├── datafield.js ├── errors.js ├── filter.js └── utils.js └── test ├── comparison.test.js ├── data.json ├── general.test.js ├── math.test.js ├── multiFilter.test.js ├── range.test.js └── sorting.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }] 6 | ], 7 | "env": { 8 | "test": { 9 | "presets": [ 10 | "env" 11 | ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | 9 | [*.json] 10 | indent_size = 4 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Error log** 17 | If applicable 18 | 19 | **Additional context** 20 | Add any other context about the problem here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Additional context** 14 | Add any other context or screenshots about the feature request here. 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | *.log 4 | *.lock 5 | coverage -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "v6.14.0" 4 | install: 5 | - yarn 6 | script: 7 | - yarn run test 8 | after_success: 9 | - bash <(curl -s https://codecov.io/bash) 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to DataField 2 | 3 | First of all, contributing is more than welcome! 4 | 5 | When contributing to this repository, please first discuss the change you wish to make via issue, 6 | email, or any other method with the owners of this repository before making a change. 7 | 8 | 9 | ## Pull Request Process 10 | 11 | 0. Write tests for your changes 12 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 13 | build. 14 | 2. Update the README.md and html in /docs folder with details of changes 15 | 16 | ## Code of Conduct 17 | 18 | ### Our Pledge 19 | 20 | In the interest of fostering an open and welcoming environment, we as 21 | contributors and maintainers pledge to making participation in our project and 22 | our community a harassment-free experience for everyone, regardless of age, body 23 | size, disability, ethnicity, gender identity and expression, level of experience, 24 | nationality, personal appearance, race, religion, or sexual identity and 25 | orientation. 26 | 27 | ### Our Standards 28 | 29 | Examples of behavior that contributes to creating a positive environment 30 | include: 31 | 32 | * Using welcoming and inclusive language 33 | * Being respectful of differing viewpoints and experiences 34 | * Gracefully accepting constructive criticism 35 | * Focusing on what is best for the community 36 | * Showing empathy towards other community members 37 | 38 | Examples of unacceptable behavior by participants include: 39 | 40 | * The use of sexualized language or imagery and unwelcome sexual attention or 41 | advances 42 | * Trolling, insulting/derogatory comments, and personal or political attacks 43 | * Public or private harassment 44 | * Publishing others' private information, such as a physical or electronic 45 | address, without explicit permission 46 | * Other conduct which could reasonably be considered inappropriate in a 47 | professional setting 48 | 49 | ### Our Responsibilities 50 | 51 | Project maintainers are responsible for clarifying the standards of acceptable 52 | behavior and are expected to take appropriate and fair corrective action in 53 | response to any instances of unacceptable behavior. 54 | 55 | Project maintainers have the right and responsibility to remove, edit, or 56 | reject comments, commits, code, wiki edits, issues, and other contributions 57 | that are not aligned to this Code of Conduct, or to ban temporarily or 58 | permanently any contributor for other behaviors that they deem inappropriate, 59 | threatening, offensive, or harmful. 60 | 61 | ### Scope 62 | 63 | This Code of Conduct applies both within project spaces and in public spaces 64 | when an individual is representing the project or its community. Examples of 65 | representing a project or community include using an official project e-mail 66 | address, posting via an official social media account, or acting as an appointed 67 | representative at an online or offline event. Representation of a project may be 68 | further defined and clarified by project maintainers. 69 | 70 | ### Enforcement 71 | 72 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 73 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 74 | complaints will be reviewed and investigated and will result in a response that 75 | is deemed necessary and appropriate to the circumstances. The project team is 76 | obligated to maintain confidentiality with regard to the reporter of an incident. 77 | Further details of specific enforcement policies may be posted separately. 78 | 79 | Project maintainers who do not follow or enforce the Code of Conduct in good 80 | faith may face temporary or permanent repercussions as determined by other 81 | members of the project's leadership. 82 | 83 | ### Attribution 84 | 85 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 86 | available at [http://contributor-covenant.org/version/1/4][version] 87 | 88 | [homepage]: http://contributor-covenant.org 89 | [version]: http://contributor-covenant.org/version/1/4/ 90 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alex Bykov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/datafield.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.DataField=e()}(this,function(){"use strict";function t(t,e){return t.hasOwnProperty(e)?t[e]:function(t,e,r){if(!t||"object"!=typeof t)return"function"==typeof r?r():r;if(!e)return t;var n=Object.assign({},t);e=e.split(".");for(var i=0;in}function r(e,r,n){var i=t(e,r);return Array.isArray(i)&&(i=i.length),n instanceof Date&&(i=new Date(i)),i>=n}function n(e,r,n){var i=t(e,r);return Array.isArray(i)&&(i=i.length),n instanceof Date&&(i=new Date(i)),ithis.data.length&&(t=this.data.length);var e=function t(e,r,n){void 0===n&&(n=[]);var i=Math.floor(Math.random()*e);return n.includes(i)||n.push(i),n.length===r?n:t(e,r,n)}(this.data.length,t),r=this.data.filter(function(t,r){return e.includes(r)});return new u(r,this.selector)},u.prototype.where=function(t){return this.selector=t,this},u.prototype.isTruthy=function(){var t=this;this.selector||c("NO_SEL");var e=this.data.filter(function(e){return o(e,t.selector)});return new u(e,this.selector)},u.prototype.isFalsy=function(){var t=this;this.selector||c("NO_SEL");var e=this.data.filter(function(e){return!o(e,t.selector)});return new u(e,this.selector)},u.prototype.eq=function(t){var e=this;this.selector&&void 0!==t||c("NO_SEL_OR_VAL");var r=this.data.filter(function(r){return s(r,e.selector,t)});return new u(r,this.selector)},u.prototype.not=function(t){var e=this;this.selector&&void 0!==t||c("NO_SEL_OR_VAL");var r=this.data.filter(function(r){return a(r,e.selector,t)});return new u(r,this.selector)},u.prototype.gt=function(t){var r=this;this.selector&&void 0!==t||c("NO_SEL_OR_VAL");var n=this.data.filter(function(n){return e(n,r.selector,t)});return new u(n,this.selector)},u.prototype.lt=function(t){var e=this;this.selector&&void 0!==t||c("NO_SEL_OR_VAL");var r=this.data.filter(function(r){return n(r,e.selector,t)});return new u(r,this.selector)},u.prototype.gte=function(t){var e=this;this.selector&&void 0!==t||c("NO_SEL_OR_VAL");var n=this.data.filter(function(n){return r(n,e.selector,t)});return new u(n,this.selector)},u.prototype.lte=function(t){var e=this;this.selector&&void 0!==t||c("NO_SEL_OR_VAL");var r=this.data.filter(function(r){return i(r,e.selector,t)});return new u(r,this.selector)},u.prototype.range=function(t,e){var i,s,a,o=this;Array.isArray(t)&&2===t.length&&(i=[t[0],t[1]],t=i[0],e=i[1]),typeof(s=t)==typeof(a=e)&&("object"==typeof s&&s instanceof Date&&a instanceof Date||"number"==typeof s||"string"==typeof s)||c("RANGE_ARG"),this.selector||c("NO_SEL");var h=this.data.filter(function(e){return r(e,o.selector,t)}).filter(function(t){return n(t,o.selector,e)});return new u(h,this.selector)},u.prototype.includes=function(e){var r=this;if(this.selector||c("NO_SEL"),void 0===e)return this;var n=this.data.filter(function(n){var i=t(n,r.selector);return Array.isArray(i)&&i.includes(e)});return new u(n,this.selector)},u.prototype.any=function(t){var e=this;if(void 0===t&&(t={}),"object"!=typeof t||!Object.keys(t).length)return this;var r=this.data.filter(function(r){return e.__checkForAny(r,t)});return new u(r,this.selector)},u.prototype.all=function(t){var e=this;if(void 0===t&&(t={}),"object"!=typeof t||!Object.keys(t).length)return this;var r=this.data.filter(function(r){return e.__checkForAll(r,t)});return new u(r,this.selector)},u.prototype.pick=function(t){if(!t)return this;if("string"!=typeof t&&c("NO_STR_VALUE"),"even"===(t=t.toLowerCase()))return new u(this.data.filter(function(t,e){return!(e%2)}));if("odd"===t)return new u(this.data.filter(function(t,e){return e%2}));if("n"===t.slice(-1)&&Number(t.slice(0,-1))){var e=Number(t.slice(0,-1));return new u(this.data.filter(function(t,r){return!(r%e)}))}c("BAD_PICK_ARG")},u.prototype.sort=function(t){void 0===t&&(t={});var e=t.by,r=t.order;void 0===r&&(r="asc");var n=t.type,i=this.__findFirstOccurrence(e);return e&&i?("desc"!==r&&(r="asc"),n||(n=typeof i),this.selector=e,"asc"===r?this.asc(n):this.desc(n)):this},u.prototype.asc=function(e){if(this.selector||c("NO_SEL"),!this.data.length)return this;var r=[];e=e||this.__getType();var n=this.selector;switch(e){case"n":case"num":case"number":r=this.data.slice().sort(function(e,r){return t(e,n)-t(r,n)});break;case"string":case"str":case"s":r=this.data.slice().sort(function(e,r){return String(t(e,n)).localeCompare(String(t(r,n)))});break;case"date":case"d":r=this.data.slice().sort(function(e,r){return Number(new Date(t(e,n)))-Number(new Date(t(r,n)))});break;case"array":case"arr":r=this.data.slice().sort(function(e,r){var i=t(e,n),s=t(r,n);if(Array.isArray(i)&&Array.isArray(s))return i.length-s.length});break;default:return this}return new u(r,this.selector)},u.prototype.desc=function(e){if(this.selector||c("NO_SEL"),!this.data.length)return this;var r=[];e=e||this.__getType();var n=this.selector;switch(e){case"num":case"number":r=this.data.slice().sort(function(e,r){return t(r,n)-t(e,n)});break;case"str":case"string":r=this.data.slice().sort(function(e,r){return String(t(r,n)).localeCompare(String(t(e,n)))});break;case"date":r=this.data.slice().sort(function(e,r){return Number(new Date(t(r,n)))-Number(new Date(t(e,n)))});break;case"arr":case"array":r=this.data.slice().sort(function(e,r){var i=t(e,n),s=t(r,n);if(Array.isArray(i)&&Array.isArray(s))return s.length-i.length});break;default:return this}return new u(r,this.selector)},u.prototype.sum=function(e,r){return void 0===e&&(e=c("NO_MATH_SEL")),void 0===r&&(r=!0),this.__reset(),this.data.reduce(function(n,i){var s=t(i,e);return r?"number"==typeof s?n+s:n:isNaN(s)?n:n+Number(s)},0)},u.prototype.avg=function(e,r){void 0===e&&(e=c("NO_MATH_SEL")),void 0===r&&(r=!0),this.__reset();var n=0,i=0;return this.data.forEach(function(s){var a=t(s,e);r?"number"==typeof a&&(i++,n+=a):isNaN(a)||(i++,n+=Number(a))}),i?n/i:0},u.prototype.median=function(e,r){void 0===e&&(e=c("NO_MATH_SEL")),void 0===r&&(r=!0),this.__reset();var n=[];if(this.data.forEach(function(i){var s=t(i,e);r?"number"==typeof s&&n.push(s):isNaN(s)||n.push(Number(s))}),0===n.length)return 0;if(1===n.length)return n[0];n.sort(function(t,e){return t-e});var i=Math.floor(n.length/2);return n.length%2?n[i]:(n[i-1]+n[i])/2},u.prototype.values=function(){return this.__reset(),this.data.slice(0)},u.prototype.toArray=function(){return this.values()},u.prototype.__reset=function(){this.selector=""},u.prototype.__getType=function(e){if(void 0===e&&(e=this.selector),e)for(var r=0;r value\r\n}\r\n\r\nfunction isGreaterOrEq (el, selector, value) {\r\n let propValue = findProp(el, selector)\r\n if (Array.isArray(propValue)) propValue = propValue.length\r\n if (value instanceof Date) propValue = new Date(propValue)\r\n return propValue >= value\r\n}\r\n\r\nfunction isLess (el, selector, value) {\r\n let propValue = findProp(el, selector)\r\n if (Array.isArray(propValue)) propValue = propValue.length\r\n if (value instanceof Date) propValue = new Date(propValue)\r\n return propValue < value\r\n}\r\n\r\nfunction isLessOrEq (el, selector, value) {\r\n let propValue = findProp(el, selector)\r\n if (Array.isArray(propValue)) propValue = propValue.length\r\n if (value instanceof Date) propValue = new Date(propValue)\r\n return propValue <= value\r\n}\r\n\r\nfunction isEq (el, selector, value) {\r\n let propValue = findProp(el, selector)\r\n if (Array.isArray(propValue)) propValue = propValue.length\r\n if (value instanceof Date) propValue = new Date(propValue)\r\n return value instanceof Date ? propValue.getTime() === value.getTime() : propValue === value\r\n}\r\n\r\nfunction isNotEq (el, selector, value) {\r\n let propValue = findProp(el, selector)\r\n if (Array.isArray(propValue)) propValue = propValue.length\r\n if (value instanceof Date) propValue = new Date(propValue)\r\n return value instanceof Date ? propValue.getTime() !== value.getTime() : propValue !== value\r\n}\r\n\r\nfunction isLike (el, selector) {\r\n return Boolean(findProp(el, selector))\r\n}\r\n\r\nexport { isGreater, isGreaterOrEq, isLess, isLessOrEq, isEq, isNotEq, isLike }\r\n","export default function error (code) {\n switch (code) {\n case 'NO_CONS':\n throw new Error('array should be passed into the DataField constructor')\n case 'NOT_ARRAY':\n throw new Error('DataField can only accept arrays')\n case 'RANGE_ARG':\n throw new Error('DataField range() method accepts 2 arguments of the same type')\n case 'NO_SEL':\n throw new Error('DataField selector not specified, use .where(selector)')\n case 'NO_SEL_OR_VAL':\n throw new Error('DataField selector or value not specified, use .where(selector) and check method arguments')\n case 'NO_MATH_SEL':\n throw new Error('DataField selector should be passed as an argument when using math methods')\n case 'NO_STR_VALUE':\n throw new Error('DataField selector .pick() expects a string')\n case 'BAD_PICK_ARG':\n throw new Error('DataField selector .pick() should have a proper argument value — \"even\", \"odd\" or \"{number}n\" (i.e. 3n for every third element)')\n default:\n throw new Error('DataField error')\n }\n}\n","import {\n findProp,\n randomTakes,\n checkTypes\n} from './utils'\nimport {\n isGreater,\n isLess,\n isLessOrEq,\n isGreaterOrEq,\n isEq,\n isNotEq,\n isLike\n} from './filter'\nimport error from './errors'\n\nexport default class DataField {\n constructor (array = error('NO_CONS'), selector) {\n if (!Array.isArray(array)) error('NOT_ARRAY')\n this.data = array.slice(0) // https://jsperf.com/cloning-arrays/3\n this.selector = selector\n this.caret = 0\n }\n\n exists (prop = this.selector) {\n const data = this.data.filter(el => findProp(el, prop) !== undefined)\n return new DataField(data, this.selector)\n }\n\n has (prop) {\n const data = this.data.filter(el => {\n const value = findProp(el, prop)\n return Array.isArray(value) ? value.length : value\n })\n return new DataField(data, this.selector)\n }\n\n take (number = 1) {\n const data = this.data.slice(this.caret, this.caret + number)\n this.caret += number\n return new DataField(data, this.selector)\n }\n\n get length () {\n this.__reset()\n return this.data.length\n }\n\n takeRandom (number = 1) {\n if (typeof number !== 'number') number = parseInt(String(number))\n if (isNaN(number)) number = 1\n number = Math.floor(number)\n if (number > this.data.length) number = this.data.length\n const selected = randomTakes(this.data.length, number)\n const data = this.data.filter((el, i) => selected.includes(i))\n return new DataField(data, this.selector)\n }\n\n where (selector) {\n this.selector = selector\n return this\n }\n\n isTruthy () {\n if (!this.selector) error('NO_SEL')\n const data = this.data.filter(el => isLike(el, this.selector))\n return new DataField(data, this.selector)\n }\n\n isFalsy () {\n if (!this.selector) error('NO_SEL')\n const data = this.data.filter(el => !isLike(el, this.selector))\n return new DataField(data, this.selector)\n }\n\n eq (value) {\n if (!this.selector || value === undefined) error('NO_SEL_OR_VAL')\n const data = this.data.filter((el) => isEq(el, this.selector, value))\n return new DataField(data, this.selector)\n }\n\n not (value) {\n if (!this.selector || value === undefined) error('NO_SEL_OR_VAL')\n const data = this.data.filter((el) => isNotEq(el, this.selector, value))\n return new DataField(data, this.selector)\n }\n\n gt (value) {\n if (!this.selector || value === undefined) error('NO_SEL_OR_VAL')\n const data = this.data.filter((el) => isGreater(el, this.selector, value))\n return new DataField(data, this.selector)\n }\n\n lt (value) {\n if (!this.selector || value === undefined) error('NO_SEL_OR_VAL')\n const data = this.data.filter((el) => isLess(el, this.selector, value))\n return new DataField(data, this.selector)\n }\n\n gte (value) {\n if (!this.selector || value === undefined) error('NO_SEL_OR_VAL')\n const data = this.data.filter((el) => isGreaterOrEq(el, this.selector, value))\n return new DataField(data, this.selector)\n }\n\n lte (value) {\n if (!this.selector || value === undefined) error('NO_SEL_OR_VAL')\n const data = this.data.filter((el) => isLessOrEq(el, this.selector, value))\n return new DataField(data, this.selector)\n }\n\n range (from, to) {\n if (Array.isArray(from) && from.length === 2) {\n [from, to] = [from[0], from[1]]\n }\n if (!checkTypes(from, to)) error('RANGE_ARG')\n if (!this.selector) error('NO_SEL')\n const data = this.data\n .filter((el) => isGreaterOrEq(el, this.selector, from))\n .filter((el) => isLess(el, this.selector, to))\n return new DataField(data, this.selector)\n }\n\n includes (value) {\n if (!this.selector) error('NO_SEL')\n if (value === undefined) return this\n const data = this.data.filter(el => {\n const prop = findProp(el, this.selector)\n return Array.isArray(prop) && prop.includes(value)\n })\n return new DataField(data, this.selector)\n }\n\n any (config = {}) {\n if (typeof config !== 'object' || !Object.keys(config).length) return this\n const data = this.data.filter((el) => this.__checkForAny(el, config))\n return new DataField(data, this.selector)\n }\n\n all (config = {}) {\n if (typeof config !== 'object' || !Object.keys(config).length) return this\n const data = this.data.filter((el) => this.__checkForAll(el, config))\n return new DataField(data, this.selector)\n }\n\n pick (value) {\n if (!value) return this\n if (typeof value !== 'string') error('NO_STR_VALUE')\n value = value.toLowerCase()\n if (value === 'even') return new DataField(this.data.filter((el, i) => !(i % 2)))\n if (value === 'odd') return new DataField(this.data.filter((el, i) => i % 2))\n if (value.slice(-1) === 'n' && !!Number(value.slice(0, -1))) {\n const rule = Number(value.slice(0, -1))\n return new DataField(this.data.filter((el, i) => !(i % rule)))\n }\n error('BAD_PICK_ARG')\n }\n\n sort ({ by, order = 'asc', type } = {}) {\n const prop = this.__findFirstOccurrence(by)\n if (!by || !prop) return this\n if (order !== 'desc') order = 'asc'\n if (!type) type = typeof prop\n this.selector = by\n return order === 'asc' ? this.asc(type) : this.desc(type)\n }\n\n asc (type) {\n if (!this.selector) error('NO_SEL')\n if (!this.data.length) return this\n let data = []\n type = type || this.__getType()\n const prop = this.selector\n switch (type) {\n case 'n':\n case 'num':\n case 'number':\n data = this.data.slice().sort((a, b) => findProp(a, prop) - findProp(b, prop))\n break\n case 'string':\n case 'str':\n case 's':\n data = this.data.slice().sort((a, b) => String(findProp(a, prop)).localeCompare(String(findProp(b, prop))))\n break\n case 'date':\n case 'd':\n data = this.data.slice().sort((a, b) => Number(new Date(findProp(a, prop))) - Number(new Date(findProp(b, prop))))\n break\n case 'array':\n case 'arr':\n data = this.data.slice().sort((a, b) => {\n const _a = findProp(a, prop)\n const _b = findProp(b, prop)\n if (Array.isArray(_a) && Array.isArray(_b)) {\n return _a.length - _b.length\n }\n })\n break\n default:\n return this\n }\n return new DataField(data, this.selector)\n }\n\n desc (type) {\n if (!this.selector) error('NO_SEL')\n if (!this.data.length) return this\n let data = []\n type = type || this.__getType()\n const prop = this.selector\n switch (type) {\n case 'num':\n case 'number':\n data = this.data.slice().sort((a, b) => findProp(b, prop) - findProp(a, prop))\n break\n case 'str':\n case 'string':\n data = this.data.slice().sort((a, b) => String(findProp(b, prop)).localeCompare(String(findProp(a, prop))))\n break\n case 'date':\n data = this.data.slice().sort((a, b) => Number(new Date(findProp(b, prop))) - Number(new Date(findProp(a, prop))))\n break\n case 'arr':\n case 'array':\n data = this.data.slice().sort((a, b) => {\n const _a = findProp(a, prop)\n const _b = findProp(b, prop)\n if (Array.isArray(_a) && Array.isArray(_b)) {\n return _b.length - _a.length\n }\n })\n break\n default:\n return this\n }\n return new DataField(data, this.selector)\n }\n\n sum (prop = error('NO_MATH_SEL'), strict = true) {\n this.__reset()\n return this.data.reduce((sum, el) => {\n const value = findProp(el, prop)\n if (strict) return typeof value === 'number' ? sum + value : sum\n return !isNaN(value) ? sum + Number(value) : sum\n }, 0)\n }\n\n avg (prop = error('NO_MATH_SEL'), strict = true) {\n this.__reset()\n let sum = 0\n let count = 0\n this.data.forEach(el => {\n const value = findProp(el, prop)\n if (strict) {\n if (typeof value === 'number') {\n count++\n sum += value\n }\n } else {\n if (!isNaN(value)) {\n count++\n sum += Number(value)\n }\n }\n })\n return count ? sum / count : 0\n }\n\n median (prop = error('NO_MATH_SEL'), strict = true) {\n this.__reset()\n const values = []\n this.data.forEach(el => {\n const value = findProp(el, prop)\n if (strict) {\n if (typeof value === 'number') {\n values.push(value)\n }\n } else {\n if (!isNaN(value)) {\n values.push(Number(value))\n }\n }\n })\n\n if (values.length === 0) {\n return 0\n } else if (values.length === 1) {\n return values[0]\n }\n\n values.sort((a, b) => a - b)\n const medianItem = Math.floor(values.length / 2)\n return values.length % 2 ? values[medianItem] : (values[medianItem - 1] + values[medianItem]) / 2\n }\n\n values () {\n this.__reset()\n return this.data.slice(0) // https://jsperf.com/cloning-arrays/3\n }\n\n toArray () {\n return this.values()\n }\n\n __reset () {\n this.selector = ''\n }\n\n __getType (selector = this.selector) {\n if (!selector) return\n for (let i = 0; i < this.data.length; i++) {\n const prop = findProp(this.data[i], selector)\n if (prop) {\n if (Array.isArray(prop)) return 'array'\n return typeof prop\n }\n }\n }\n\n __findFirstOccurrence (selector) {\n if (!selector) return\n for (let i = 0; i < this.data.length; i++) {\n const prop = findProp(this.data[i], selector)\n if (prop) {\n return prop\n }\n }\n }\n\n __checkForAny (el, config) {\n const props = Object.keys(config)\n for (let prop of props) {\n switch (prop) {\n case 'gt':\n if (isGreater(el, this.selector, config[prop])) return true\n break\n case 'gte':\n if (isGreaterOrEq(el, this.selector, config[prop])) return true\n break\n case 'lt':\n if (isLess(el, this.selector, config[prop])) return true\n break\n case 'lte':\n if (isLessOrEq(el, this.selector, config[prop])) return true\n break\n case 'eq':\n if (isEq(el, this.selector, config[prop])) return true\n break\n case 'not':\n if (isNotEq(el, this.selector, config[prop])) return true\n break\n case 'is':\n if (config[prop] === isLike(el, this.selector)) return true\n break\n case 'range':\n if (\n Array.isArray(config[prop]) && config[prop].length === 2 &&\n isGreaterOrEq(el, this.selector, config[prop][0]) &&\n isLess(el, this.selector, config[prop][1])) return true\n break\n default:\n }\n }\n }\n\n __checkForAll (el, config) {\n const props = Object.keys(config)\n for (let prop of props) {\n switch (prop) {\n case 'gt':\n if (!isGreater(el, this.selector, config[prop])) return\n break\n case 'gte':\n if (!isGreaterOrEq(el, this.selector, config[prop])) return\n break\n case 'lt':\n if (!isLess(el, this.selector, config[prop])) return\n break\n case 'lte':\n if (!isLessOrEq(el, this.selector, config[prop])) return\n break\n case 'eq':\n if (!isEq(el, this.selector, config[prop])) return\n break\n case 'not':\n if (!isNotEq(el, this.selector, config[prop])) return\n break\n case 'is':\n if (config[prop] !== isLike(el, this.selector)) return\n break\n case 'range':\n if (\n Array.isArray(config[prop]) && config[prop].length === 2 &&\n !(isGreaterOrEq(el, this.selector, config[prop][0]) &&\n isLess(el, this.selector, config[prop][1]))) return\n break\n default:\n }\n }\n return true\n }\n}\n"],"names":["findProp","el","prop","hasOwnProperty","obj","path","fallback","let","o","Object","assign","split","i","length","traverseKeys","isGreater","selector","value","propValue","Array","isArray","Date","isGreaterOrEq","isLess","isLessOrEq","isEq","getTime","isNotEq","isLike","Boolean","error","code","Error","DataField","array","this","data","slice","caret","exists","filter","undefined","has","const","take","number","prototypeAccessors","__reset","takeRandom","parseInt","String","isNaN","Math","floor","selected","randomTakes","len","num","collection","index","random","includes","push","where","isTruthy","isFalsy","eq","not","gt","lt","gte","lte","range","from","to","a","b","any","config","keys","__checkForAny","all","__checkForAll","pick","toLowerCase","Number","rule","sort","ref","__findFirstOccurrence","by","order","type","asc","desc","__getType","localeCompare","_a","_b","sum","strict","reduce","avg","count","forEach","median","values","medianItem","toArray"],"mappings":"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"} -------------------------------------------------------------------------------- /docs/datafield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexbykoff/datafield/43fe57d3daa5118b4566d2973d0d7c33030c8d6a/docs/datafield.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DataField — Javascript Library 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 83 |
84 |
85 |
86 |
87 |
DataField.js — v0.3.0
88 |
Select, sort, filter and perform maths and analysis on your arrays of data
89 |
Zero-dependency Javascript library for Node and browsers that works with collections 90 |
91 |
92 |
Currently in early beta — code contributions are more than welcome
93 |
94 |
95 | 96 | 97 |
98 |
99 |
100 |
101 |
What is DataField
102 |

DataField is a library that helps you wrangle your awesome collections of data you obtain from different 103 | sources.

104 |

Imagine you are building a web application that deals with users. You make an API request and receive an 105 | array 106 | of 100 entries which look like this one below:

107 |
108 |         
109 |     {
110 |       "_id": "5b420ae94fe6464ff91f5de8",
111 |       "index": 0,
112 |       "guid": "871eebf0-9983-4eb5-a0b5-59372a2fbecd",
113 |       "isActive": true,
114 |       "balance": "$1,268.06",
115 |       "age": 41,
116 |       "name": {
117 |         "first": "Pearlie",
118 |         "last": "Osborne"
119 |       },
120 |       "company": "PIVITOL",
121 |       "email": "pearlie.osborne@pivitol.net",
122 |       "phone": "+1 (992) 418-2307",
123 |       "address": "190 River Street, Spelter, Tennessee, 1088",
124 |       "registered": "Monday, April 18, 2016 7:35 AM",
125 |       "tags": ["ad", "magna", "aliqua"],
126 |       "friends": [{"id": 0, "name": "Whitney Snow"}, {"id": 1, "name": "Garza Hernandez"}, {"id": 2,"name": "Lourdes Conley"}]
127 |     }
128 |         
129 |       
130 |

With this library it is rather easy to perform various actions on your data.

131 |
How It Works
132 |
const users = new DataField(arrayOfUsers)
133 |

Now your data is stored in an instance of DataField class.

134 |

Each method that does any kind of selection or filtering returns a new instance of DataField and 135 | can be chained.

136 |

Math methods return primitives and can not be chained

137 |

To extract your data use .values() or .toArray() 138 |

139 |

Now lets filter our data. We need users who are 30 years old or older, but not 41 years old and have at least 140 | 2 141 | friends, but less than 142 | 10. Also we want our list sorted by last name in descending order. After that we are done so we want an array 143 | out of 144 | that:

145 |
users.where('age').gte(30).not(41).where('friends').range(2, 10).sort({by: 'name.last', order: 'desc'}).toArray()
146 |

Or you can go more object-oriented way (this one below is kinda weird request although):

147 |

148 | users.where('age').any({
149 |   range: [8, 88],
150 |   lte: 18,
151 |   gt: 60,
152 |   not: 42,
153 |   is: false
154 | })
155 |   .toArray()
156 |

That's it. API is short and simple. Look to the left – there is a list of methods.

157 |
Open console in your browser. There is a variable users there you can play with — it is 158 | a DataField instance with 100 entries in it. 159 |
160 |
161 |
162 |
163 |
164 |
Installation
165 |
166 |
167 | npm: 168 |
npm i datafield
169 |
170 | cdn: 171 |
https://unpkg.com/datafield@latest
172 |
173 |
174 | 175 |
176 |
177 |
API
178 |
Basic Operations. Filtering
179 | 180 | 181 |
182 |
183 |
.where(string)
184 |

Basic property selector. All subsequent operations will be based on this selector. 185 | If no selector present an error will be thrown

186 |
187 |               
188 | users.where('age').eq(30)
189 |               
190 |             
191 |

Nested properties can be selected using dot notation within a string

192 |
193 |               
194 | users.where('name.last').gte('B')
195 |               
196 |             
197 |

If you need to filter your data based on multiple properties you can chain them

198 |
199 |               
200 | users
201 |     .where('age').gte(18)
202 |     .where('isActive').isTruthy()
203 |     .where('friends').range(2,20)
204 |               
205 |             
206 |
207 |
208 |
209 | 210 | 211 |
212 |
213 |
.values()
214 |

Unwraps DataField instance into an array. toArray() does the same job. 215 |

216 |
217 |               users.toArray().map(user => user.age)
218 |             
219 |
220 |
221 |
222 |
223 |
224 |
toArray()
225 | Another syntax for values() 226 |
227 |
228 |
229 | 230 | 231 |
232 |
233 |
exists([property])
234 |

Selects entries where property exists. If no property value is passed then library tries 235 | to use the last selector

236 |
237 |               
238 | // this is okay:
239 | users.where('email').exists()
240 | // this is okay too:
241 | users.exists('email')
242 | // this will throw an error:
243 | users.exists()
244 |               
245 |             
246 |
247 |
248 |
249 |
250 |
251 |
has(property)
252 |

Selects entries where property exists and has truthy value.

253 |
254 |               
255 | users.has('email').where('age').gte(18).median()
256 | // selects users who have their email added to the profile, 18 years or older and return the age median of such users
257 |               
258 |             
259 |
260 |
261 |
262 | 263 | 264 |
265 |
266 |
take([number])
267 |

Returns Number entries from DataField object, starting from the first one. 268 | If value is not provided then returns one entry. If value is greater than amount of entries left - returns 269 | the rest of them

270 |
271 |               
272 | users.where('age').asc().take(10)
273 |               
274 |             
275 |
276 | Important! History of take() is stored in an instance the method was called 277 | on. Consider the following: 278 |
279 |
280 |               
281 | const users = new DataField(data)  // 12 entries in an array
282 | firstFive = users.take(5) // indices 0 - 4
283 | SecondFive = users.take(5) // indices 5 - 9
284 | restOfUsers = users.take(5) // indices 9 - end of array
285 |               
286 |             
287 |
288 |
289 |
290 | 291 | 292 |
293 |
294 |
takeRandom([Number])
295 |

Returns Number random entries from DataField object. 296 | If value is not provided then returns one entry. Unlike take() method does 297 | not track its own history

298 |
299 |               
300 | users.takeRandom() // returns one random entry
301 |               
302 |             
303 |
304 |
305 |
306 | 307 | 308 |
309 |
310 |
pick([String])
311 |

Returns entries from DataField object based filtered by arguments. 312 | If value is not provided then returns unchanged data set

313 |

Possible values — "even", "odd" or "{number}n" (i.e. "3n") — return new DataField of every other, every 314 | odd or every 3rd item respectively

315 |
316 |               
317 | users.pick("5n") // returns every 5th item in the data set
318 |               
319 |             
320 |
321 |
322 |
323 | 324 | 325 |
326 |
327 |
length
328 |

Getter. Returns the number of entries

329 |
330 |               
331 | users.length // 100
332 |               
333 |             
334 |
335 |
336 |
337 | 338 |
Comparison
339 | 340 | 341 |
342 |
343 |
eq(value)
344 |
not(value)
345 |
gt(value)
346 |
gte(value)
347 |
lt(value)
348 |
lte(value)
349 |

Selects entries by condition. Currently supports Number, String, Date 350 | values

351 |
352 |               
353 | users
354 |     .where('age').eq(42)
355 |     .where('registered').gte(new Date("Jan 1 2017")).lte(new Date("Dec 31 2018"))
356 |     .where('company').not('COMVOY')
357 |               
358 |             
359 |
360 |
361 |
362 | 363 | 364 |
365 |
366 |
isTruthy()
367 |

Selects entries with truthy selector value (one that evaluates to true 368 | in Javascript)

369 |
370 |               
371 | users.where('isActive').isTruthy()
372 |               
373 |             
374 |
375 |
376 |
377 | 378 | 379 |
380 |
381 |
isFalsy()
382 |

Selects entries with falsy selector value (one that evaluates to false 383 | in Javascript)

384 |
385 |               
386 | users.where('isActive').isFalsy()
387 |               
388 |             
389 |
390 |
391 |
392 | 393 | 394 |
395 |
396 |
includes(value)
397 |

Selects entries which array selectors include value Works similar to ES7 includes

399 |
400 |               
401 | users.where('tags').includes('nostrud')
402 |               
403 |             
404 |
405 |
406 |
407 | 408 | 409 |
410 |
411 |
range(from, to)
412 |

Selects entries with selector's value within the given range.

413 |

Currently supports Number, String, Date, Array.length

414 |
415 |               
416 | const from = new Date("Feb 23 2014")
417 | const to = new Date("May 12 2017")
418 | users.where('registered').range(from, to)
419 |               
420 |             
421 |
422 |
423 |
424 | 425 |
Complex filtering
426 | 427 | 428 |
429 |
430 |
all(config)
431 |
any(config)
432 |

Selects entries based on configuration object.

433 |

.all() is an AND logic — entry must 434 | satisfy 435 | all conditions

436 |

.any() is an OR-like filter — entry must 437 | satisfy at least one condition

438 |

possible properties: gt, gte, lt, lte, eq, not, range, is

439 |
440 |
is
441 | is a boolean condition same as isTruthy / isFalsy methods 443 |
444 |
445 |
range
446 | value should be an array of with the length of 2 — 447 |
[from, to]
448 |
449 |
450 |               
451 | users.where('age').all({
452 |   range: [16, 33],
453 |   not: 27
454 | })
455 | 
456 | users.where('age').any({
457 |   is: false,
458 |   eq: 42
459 | })
460 |             
461 |
462 |
463 |
464 | 465 |
Sorting
466 | 467 | 468 |
469 |
470 |
sort(config)
471 |

Sorts entries based on config options

472 |

Config:

473 |
474 |               
475 | {
476 |   by: 'property', // <-- selector. MANDATORY
477 |   order: 'asc' / 'desc' // <-- sorting order. OPTIONAL
478 |   type: 'num' / 'str' / 'date' // type of value. OPTIONAL
479 | }
480 |               
481 |             
482 |

If type is not provided library will try to guess it. If you want to sort by date make sure to 483 | explicitly add that to the config, otherwise it will be treated as a string

484 |
485 |               
486 | users.where('age').gte(18).sort({by: "name.last", order: "desc"})
487 |               
488 |             
489 |
490 |
491 |
492 | 493 | 494 |
495 |
496 |
asc()
497 |
desc()
498 |

Sorts by selector in ascending / descending order

499 |
500 |               
501 | users.where('company').asc()
502 | // or
503 | users.where('age').desc()
504 |               
505 |             
506 |
507 |
508 |
509 | 510 |
Math operations
511 | 512 | 513 |
514 |
515 |
sum(property, [strict])
516 |
avg(property, [strict])
517 |
median(property, [strict])
518 |

Returns a result of mathematical operation on. Ignored if selector is not of type Number. If strict parameter is set to false attempts to coerce types

521 |
522 |               
523 | users.where('isActive').isTruthy().sum('age') // 2083
524 | users.where('isActive').isTruthy().sum('age', false) // 2107 – converted string to a number
525 |               
526 |             
527 |
528 |
529 |
530 | 531 | 532 |
533 | 534 |
535 |
536 |
537 | 538 | 542 | 543 | 544 | -------------------------------------------------------------------------------- /docs/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, body { 6 | margin: 0; 7 | padding: 0; 8 | font-family: 'Source Sans Pro', sans-serif; 9 | font-weight: 400; 10 | font-size: 16px; 11 | } 12 | 13 | .menu { 14 | width: 16rem; 15 | position: fixed; 16 | top: 0; 17 | bottom: 0; 18 | background-color: #ffebd4; 19 | overflow-x: hidden; 20 | overflow-y: auto; 21 | height: 100vh; 22 | } 23 | 24 | .main { 25 | margin-left: 16rem; 26 | padding-left: 1rem; 27 | 28 | } 29 | 30 | h1 { 31 | font-weight: inherit; 32 | } 33 | 34 | .hidden { 35 | display: none; 36 | } 37 | 38 | .menu ul { 39 | list-style-type: none; 40 | padding-left: .5rem; 41 | } 42 | 43 | .menu > ul { 44 | padding-left: 1rem; 45 | } 46 | 47 | .menu li { 48 | padding: .125rem .25rem; 49 | } 50 | 51 | .menu a { 52 | text-decoration-line: none; 53 | display: inline-block; 54 | } 55 | 56 | .menu a:hover { 57 | color: orangered; 58 | border-bottom: 1px solid forestgreen; 59 | } 60 | 61 | .first-level { 62 | color: #100c5f; 63 | border-bottom: 1px dashed #100c5f; 64 | font-weight: bolder; 65 | font-size: 1.25rem; 66 | } 67 | 68 | .second-level { 69 | color: #100c5f; 70 | border-bottom: 1px dashed #100c5f; 71 | font-weight: bolder; 72 | } 73 | 74 | .section li a { 75 | color: #100c5f; 76 | border-bottom: 1px dashed #100c5f; 77 | font-weight: normal; 78 | } 79 | 80 | .menu .section { 81 | padding-bottom: .5rem; 82 | } 83 | 84 | .menu h2 { 85 | font-family: "Arial Black", Arial, sans-serif; 86 | color: #777; 87 | font-weight: bold; 88 | padding-left: 1rem; 89 | } 90 | 91 | .main pre { 92 | padding: 0 !important; 93 | margin: 0 !important; 94 | line-height: 0; 95 | } 96 | 97 | .main pre code, .main pre code span { 98 | font-size: 14px !important; 99 | line-height: 1.25; 100 | } 101 | 102 | .logo { 103 | margin: 0 auto; 104 | } 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datafield", 3 | "keywords": [ 4 | "arrays", 5 | "collections", 6 | "data", 7 | "sorting", 8 | "filtering", 9 | "database" 10 | ], 11 | "homepage": "https://tomkallen.github.io/datafield/", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/tomkallen/datafield.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/tomkallen/datafield/issues", 18 | "email": "comradebykoff@gmail.com" 19 | }, 20 | "version": "0.3.0", 21 | "description": "Sort, select, filter, evaluate and perform maths on your arrays of data", 22 | "main": "./dist/datafield.min.js", 23 | "module": "./src/datafield.js", 24 | "scripts": { 25 | "test": "npm run lint && jest && codecov", 26 | "build": "npm run clean && rollup --config", 27 | "clean": "rimraf dist", 28 | "lint": "standard src/*.js --fix --verbose | snazzy" 29 | }, 30 | "husky": { 31 | "hooks": { 32 | "pre-commit": "npm run test && npm run build && git add ." 33 | } 34 | }, 35 | "jest": { 36 | "coverageDirectory": "./coverage/", 37 | "collectCoverage": true, 38 | "collectCoverageFrom": [ 39 | "src/**/*.js", 40 | "!**/node_modules/**", 41 | "!**/test/**" 42 | ] 43 | }, 44 | "standard": { 45 | "parser": "babel-eslint" 46 | }, 47 | "author": "Alex Bykov", 48 | "license": "MIT", 49 | "devDependencies": { 50 | "babel-cli": "6.26.0", 51 | "babel-eslint": "10.0.1", 52 | "babel-preset-env": "1.7.0", 53 | "babel-preset-flow": "6.23.0", 54 | "codecov": "3.1.0", 55 | "husky": "1.1.4", 56 | "jest": "23.6.0", 57 | "rimraf": "2.6.2", 58 | "rollup": "0.67.1", 59 | "rollup-plugin-buble": "0.19.4", 60 | "rollup-plugin-commonjs": "9.2.0", 61 | "rollup-plugin-node-resolve": "3.4.0", 62 | "rollup-plugin-terser": "3.0.0", 63 | "snazzy": "8.0.0", 64 | "standard": "12.0.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

Sort, select, filter and perform maths and analysis on your arrays of data

6 |

:bear: version 0.3.0 is out

7 | 8 | [![codecov](https://codecov.io/gh/tomkallen/datafield/branch/master/graph/badge.svg)](https://codecov.io/gh/tomkallen/datafield) 9 | [![Build Status](https://travis-ci.org/tomkallen/datafield.svg?branch=master)](https://travis-ci.org/tomkallen/datafield) 10 | [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) 11 | [![npm version](https://badge.fury.io/js/datafield.svg)](https://badge.fury.io/js/datafield) 12 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 13 | 14 | 15 | [:page_facing_up: Read the documentation here](https://tomkallen.github.io/datafield/) 16 | [:cat: Contribute for the greater good](https://github.com/tomkallen/datafield/blob/master/CONTRIBUTING.md) 17 | 18 | ## What is DataField 19 | 20 | DataField is a library that helps you wrangle your awesome collections of data you obtain from different sources. 21 | 22 | Imagine you are building a web application that deals with users. You make an API request and receive an array of 100 entries which look like this one below: 23 | 24 | { 25 | "_id": "5b420ae94fe6464ff91f5de8", 26 | "index": 0, 27 | "guid": "871eebf0-9983-4eb5-a0b5-59372a2fbecd", 28 | "isActive": true, 29 | "balance": "$1,268.06", 30 | "age": 41, 31 | "name": { 32 | "first": "Pearlie", 33 | "last": "Osborne" 34 | }, 35 | "company": "PIVITOL", 36 | "email": "pearlie.osborne@pivitol.net", 37 | "phone": "+1 (992) 418-2307", 38 | "address": "190 River Street, Spelter, Tennessee, 1088", 39 | "registered": "Monday, April 18, 2016 7:35 AM", 40 | "tags": ["ad", "magna", "aliqua"], 41 | "friends": [{"id": 0, "name": "Whitney Snow"}, {"id": 1, "name": "Garza Hernandez"}, {"id": 2,"name": "Lourdes Conley"}] 42 | } 43 | 44 | 45 | With this library it is rather easy to perform various actions on your data. 46 | 47 | #### How It Works 48 | 49 | const users = new DataField(arrayOfUsers) 50 | 51 | Now your data is stored in an instance of DataField class. 52 | 53 | Each method that performs any kind of selection or filtering returns a **new instance** of DataField and can be chained. 54 | 55 | Math methods return primitives and can not be chained 56 | 57 | To extract your data use `.values()` or `toArray()` 58 | 59 | 60 | Lets filter our data. We need users who are 30 years old or older, but not 41 years old and have at least 2 friends, but less than 10. Also we want our list sorted by last name in descending order. Then we are done so we want an array out of that: 61 | 62 | users.where('age').gte(30).not(41).where('friends').range(2, 10).sort({by: 'name.last', order: 'desc'}).toArray() 63 | 64 | Or you can go more *object-oriented* way (this one below is kinda weird request although): 65 | 66 | ```js 67 | users.where('age').any({ 68 | range: [8, 88], 69 | lte: 18, 70 | gt: 60, 71 | not: 42, 72 | is: false 73 | }) 74 | ``` 75 | 76 | 77 | That's it. API is short and simple. 78 | Also, read the [Documentation](https://tomkallen.github.io/datafield/) 79 | 80 | `npm i datafield` 81 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import buble from 'rollup-plugin-buble' 4 | import pkg from './package.json' 5 | import { terser } from 'rollup-plugin-terser' 6 | 7 | export default [{ 8 | input: 'src/datafield.js', 9 | output: { 10 | file: pkg.main, 11 | name: 'DataField', 12 | sourcemap: true, 13 | format: 'umd' 14 | }, 15 | plugins: [ 16 | resolve(), 17 | commonjs(), 18 | terser(), 19 | buble({transforms: { dangerousForOf: true }}) 20 | ] 21 | }] 22 | -------------------------------------------------------------------------------- /src/datafield.js: -------------------------------------------------------------------------------- 1 | import { 2 | findProp, 3 | randomTakes, 4 | checkTypes 5 | } from './utils' 6 | import { 7 | isGreater, 8 | isLess, 9 | isLessOrEq, 10 | isGreaterOrEq, 11 | isEq, 12 | isNotEq, 13 | isLike 14 | } from './filter' 15 | import error from './errors' 16 | 17 | export default class DataField { 18 | constructor (array = error('NO_CONS'), selector) { 19 | if (!Array.isArray(array)) error('NOT_ARRAY') 20 | this.data = array.slice(0) // https://jsperf.com/cloning-arrays/3 21 | this.selector = selector 22 | this.caret = 0 23 | } 24 | 25 | exists (prop = this.selector) { 26 | const data = this.data.filter(el => findProp(el, prop) !== undefined) 27 | return new DataField(data, this.selector) 28 | } 29 | 30 | has (prop) { 31 | const data = this.data.filter(el => { 32 | const value = findProp(el, prop) 33 | return Array.isArray(value) ? value.length : value 34 | }) 35 | return new DataField(data, this.selector) 36 | } 37 | 38 | take (number = 1) { 39 | const data = this.data.slice(this.caret, this.caret + number) 40 | this.caret += number 41 | return new DataField(data, this.selector) 42 | } 43 | 44 | get length () { 45 | this.__reset() 46 | return this.data.length 47 | } 48 | 49 | takeRandom (number = 1) { 50 | if (typeof number !== 'number') number = parseInt(String(number)) 51 | if (isNaN(number)) number = 1 52 | number = Math.floor(number) 53 | if (number > this.data.length) number = this.data.length 54 | const selected = randomTakes(this.data.length, number) 55 | const data = this.data.filter((el, i) => selected.includes(i)) 56 | return new DataField(data, this.selector) 57 | } 58 | 59 | where (selector) { 60 | this.selector = selector 61 | return this 62 | } 63 | 64 | isTruthy () { 65 | if (!this.selector) error('NO_SEL') 66 | const data = this.data.filter(el => isLike(el, this.selector)) 67 | return new DataField(data, this.selector) 68 | } 69 | 70 | isFalsy () { 71 | if (!this.selector) error('NO_SEL') 72 | const data = this.data.filter(el => !isLike(el, this.selector)) 73 | return new DataField(data, this.selector) 74 | } 75 | 76 | eq (value) { 77 | if (!this.selector || value === undefined) error('NO_SEL_OR_VAL') 78 | const data = this.data.filter((el) => isEq(el, this.selector, value)) 79 | return new DataField(data, this.selector) 80 | } 81 | 82 | not (value) { 83 | if (!this.selector || value === undefined) error('NO_SEL_OR_VAL') 84 | const data = this.data.filter((el) => isNotEq(el, this.selector, value)) 85 | return new DataField(data, this.selector) 86 | } 87 | 88 | gt (value) { 89 | if (!this.selector || value === undefined) error('NO_SEL_OR_VAL') 90 | const data = this.data.filter((el) => isGreater(el, this.selector, value)) 91 | return new DataField(data, this.selector) 92 | } 93 | 94 | lt (value) { 95 | if (!this.selector || value === undefined) error('NO_SEL_OR_VAL') 96 | const data = this.data.filter((el) => isLess(el, this.selector, value)) 97 | return new DataField(data, this.selector) 98 | } 99 | 100 | gte (value) { 101 | if (!this.selector || value === undefined) error('NO_SEL_OR_VAL') 102 | const data = this.data.filter((el) => isGreaterOrEq(el, this.selector, value)) 103 | return new DataField(data, this.selector) 104 | } 105 | 106 | lte (value) { 107 | if (!this.selector || value === undefined) error('NO_SEL_OR_VAL') 108 | const data = this.data.filter((el) => isLessOrEq(el, this.selector, value)) 109 | return new DataField(data, this.selector) 110 | } 111 | 112 | range (from, to) { 113 | if (Array.isArray(from) && from.length === 2) { 114 | [from, to] = [from[0], from[1]] 115 | } 116 | if (!checkTypes(from, to)) error('RANGE_ARG') 117 | if (!this.selector) error('NO_SEL') 118 | const data = this.data 119 | .filter((el) => isGreaterOrEq(el, this.selector, from)) 120 | .filter((el) => isLess(el, this.selector, to)) 121 | return new DataField(data, this.selector) 122 | } 123 | 124 | includes (value) { 125 | if (!this.selector) error('NO_SEL') 126 | if (value === undefined) return this 127 | const data = this.data.filter(el => { 128 | const prop = findProp(el, this.selector) 129 | return Array.isArray(prop) && prop.includes(value) 130 | }) 131 | return new DataField(data, this.selector) 132 | } 133 | 134 | any (config = {}) { 135 | if (typeof config !== 'object' || !Object.keys(config).length) return this 136 | const data = this.data.filter((el) => this.__checkForAny(el, config)) 137 | return new DataField(data, this.selector) 138 | } 139 | 140 | all (config = {}) { 141 | if (typeof config !== 'object' || !Object.keys(config).length) return this 142 | const data = this.data.filter((el) => this.__checkForAll(el, config)) 143 | return new DataField(data, this.selector) 144 | } 145 | 146 | pick (value) { 147 | if (!value) return this 148 | if (typeof value !== 'string') error('NO_STR_VALUE') 149 | value = value.toLowerCase() 150 | if (value === 'even') return new DataField(this.data.filter((el, i) => !(i % 2))) 151 | if (value === 'odd') return new DataField(this.data.filter((el, i) => i % 2)) 152 | if (value.slice(-1) === 'n' && !!Number(value.slice(0, -1))) { 153 | const rule = Number(value.slice(0, -1)) 154 | return new DataField(this.data.filter((el, i) => !(i % rule))) 155 | } 156 | error('BAD_PICK_ARG') 157 | } 158 | 159 | sort ({ by, order = 'asc', type } = {}) { 160 | const prop = this.__findFirstOccurrence(by) 161 | if (!by || !prop) return this 162 | if (order !== 'desc') order = 'asc' 163 | if (!type) type = typeof prop 164 | this.selector = by 165 | return order === 'asc' ? this.asc(type) : this.desc(type) 166 | } 167 | 168 | asc (type) { 169 | if (!this.selector) error('NO_SEL') 170 | if (!this.data.length) return this 171 | let data = [] 172 | type = type || this.__getType() 173 | const prop = this.selector 174 | switch (type) { 175 | case 'n': 176 | case 'num': 177 | case 'number': 178 | data = this.data.slice().sort((a, b) => findProp(a, prop) - findProp(b, prop)) 179 | break 180 | case 'string': 181 | case 'str': 182 | case 's': 183 | data = this.data.slice().sort((a, b) => String(findProp(a, prop)).localeCompare(String(findProp(b, prop)))) 184 | break 185 | case 'date': 186 | case 'd': 187 | data = this.data.slice().sort((a, b) => Number(new Date(findProp(a, prop))) - Number(new Date(findProp(b, prop)))) 188 | break 189 | case 'array': 190 | case 'arr': 191 | data = this.data.slice().sort((a, b) => { 192 | const _a = findProp(a, prop) 193 | const _b = findProp(b, prop) 194 | if (Array.isArray(_a) && Array.isArray(_b)) { 195 | return _a.length - _b.length 196 | } 197 | }) 198 | break 199 | default: 200 | return this 201 | } 202 | return new DataField(data, this.selector) 203 | } 204 | 205 | desc (type) { 206 | if (!this.selector) error('NO_SEL') 207 | if (!this.data.length) return this 208 | let data = [] 209 | type = type || this.__getType() 210 | const prop = this.selector 211 | switch (type) { 212 | case 'num': 213 | case 'number': 214 | data = this.data.slice().sort((a, b) => findProp(b, prop) - findProp(a, prop)) 215 | break 216 | case 'str': 217 | case 'string': 218 | data = this.data.slice().sort((a, b) => String(findProp(b, prop)).localeCompare(String(findProp(a, prop)))) 219 | break 220 | case 'date': 221 | data = this.data.slice().sort((a, b) => Number(new Date(findProp(b, prop))) - Number(new Date(findProp(a, prop)))) 222 | break 223 | case 'arr': 224 | case 'array': 225 | data = this.data.slice().sort((a, b) => { 226 | const _a = findProp(a, prop) 227 | const _b = findProp(b, prop) 228 | if (Array.isArray(_a) && Array.isArray(_b)) { 229 | return _b.length - _a.length 230 | } 231 | }) 232 | break 233 | default: 234 | return this 235 | } 236 | return new DataField(data, this.selector) 237 | } 238 | 239 | sum (prop = error('NO_MATH_SEL'), strict = true) { 240 | this.__reset() 241 | return this.data.reduce((sum, el) => { 242 | const value = findProp(el, prop) 243 | if (strict) return typeof value === 'number' ? sum + value : sum 244 | return !isNaN(value) ? sum + Number(value) : sum 245 | }, 0) 246 | } 247 | 248 | avg (prop = error('NO_MATH_SEL'), strict = true) { 249 | this.__reset() 250 | let sum = 0 251 | let count = 0 252 | this.data.forEach(el => { 253 | const value = findProp(el, prop) 254 | if (strict) { 255 | if (typeof value === 'number') { 256 | count++ 257 | sum += value 258 | } 259 | } else { 260 | if (!isNaN(value)) { 261 | count++ 262 | sum += Number(value) 263 | } 264 | } 265 | }) 266 | return count ? sum / count : 0 267 | } 268 | 269 | median (prop = error('NO_MATH_SEL'), strict = true) { 270 | this.__reset() 271 | const values = [] 272 | this.data.forEach(el => { 273 | const value = findProp(el, prop) 274 | if (strict) { 275 | if (typeof value === 'number') { 276 | values.push(value) 277 | } 278 | } else { 279 | if (!isNaN(value)) { 280 | values.push(Number(value)) 281 | } 282 | } 283 | }) 284 | 285 | if (values.length === 0) { 286 | return 0 287 | } else if (values.length === 1) { 288 | return values[0] 289 | } 290 | 291 | values.sort((a, b) => a - b) 292 | const medianItem = Math.floor(values.length / 2) 293 | return values.length % 2 ? values[medianItem] : (values[medianItem - 1] + values[medianItem]) / 2 294 | } 295 | 296 | values () { 297 | this.__reset() 298 | return this.data.slice(0) // https://jsperf.com/cloning-arrays/3 299 | } 300 | 301 | toArray () { 302 | return this.values() 303 | } 304 | 305 | __reset () { 306 | this.selector = '' 307 | } 308 | 309 | __getType (selector = this.selector) { 310 | if (!selector) return 311 | for (let i = 0; i < this.data.length; i++) { 312 | const prop = findProp(this.data[i], selector) 313 | if (prop) { 314 | if (Array.isArray(prop)) return 'array' 315 | return typeof prop 316 | } 317 | } 318 | } 319 | 320 | __findFirstOccurrence (selector) { 321 | if (!selector) return 322 | for (let i = 0; i < this.data.length; i++) { 323 | const prop = findProp(this.data[i], selector) 324 | if (prop) { 325 | return prop 326 | } 327 | } 328 | } 329 | 330 | __checkForAny (el, config) { 331 | const props = Object.keys(config) 332 | for (let prop of props) { 333 | switch (prop) { 334 | case 'gt': 335 | if (isGreater(el, this.selector, config[prop])) return true 336 | break 337 | case 'gte': 338 | if (isGreaterOrEq(el, this.selector, config[prop])) return true 339 | break 340 | case 'lt': 341 | if (isLess(el, this.selector, config[prop])) return true 342 | break 343 | case 'lte': 344 | if (isLessOrEq(el, this.selector, config[prop])) return true 345 | break 346 | case 'eq': 347 | if (isEq(el, this.selector, config[prop])) return true 348 | break 349 | case 'not': 350 | if (isNotEq(el, this.selector, config[prop])) return true 351 | break 352 | case 'is': 353 | if (config[prop] === isLike(el, this.selector)) return true 354 | break 355 | case 'range': 356 | if ( 357 | Array.isArray(config[prop]) && config[prop].length === 2 && 358 | isGreaterOrEq(el, this.selector, config[prop][0]) && 359 | isLess(el, this.selector, config[prop][1])) return true 360 | break 361 | default: 362 | } 363 | } 364 | } 365 | 366 | __checkForAll (el, config) { 367 | const props = Object.keys(config) 368 | for (let prop of props) { 369 | switch (prop) { 370 | case 'gt': 371 | if (!isGreater(el, this.selector, config[prop])) return 372 | break 373 | case 'gte': 374 | if (!isGreaterOrEq(el, this.selector, config[prop])) return 375 | break 376 | case 'lt': 377 | if (!isLess(el, this.selector, config[prop])) return 378 | break 379 | case 'lte': 380 | if (!isLessOrEq(el, this.selector, config[prop])) return 381 | break 382 | case 'eq': 383 | if (!isEq(el, this.selector, config[prop])) return 384 | break 385 | case 'not': 386 | if (!isNotEq(el, this.selector, config[prop])) return 387 | break 388 | case 'is': 389 | if (config[prop] !== isLike(el, this.selector)) return 390 | break 391 | case 'range': 392 | if ( 393 | Array.isArray(config[prop]) && config[prop].length === 2 && 394 | !(isGreaterOrEq(el, this.selector, config[prop][0]) && 395 | isLess(el, this.selector, config[prop][1]))) return 396 | break 397 | default: 398 | } 399 | } 400 | return true 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /src/errors.js: -------------------------------------------------------------------------------- 1 | export default function error (code) { 2 | switch (code) { 3 | case 'NO_CONS': 4 | throw new Error('array should be passed into the DataField constructor') 5 | case 'NOT_ARRAY': 6 | throw new Error('DataField can only accept arrays') 7 | case 'RANGE_ARG': 8 | throw new Error('DataField range() method accepts 2 arguments of the same type') 9 | case 'NO_SEL': 10 | throw new Error('DataField selector not specified, use .where(selector)') 11 | case 'NO_SEL_OR_VAL': 12 | throw new Error('DataField selector or value not specified, use .where(selector) and check method arguments') 13 | case 'NO_MATH_SEL': 14 | throw new Error('DataField selector should be passed as an argument when using math methods') 15 | case 'NO_STR_VALUE': 16 | throw new Error('DataField selector .pick() expects a string') 17 | case 'BAD_PICK_ARG': 18 | throw new Error('DataField selector .pick() should have a proper argument value — "even", "odd" or "{number}n" (i.e. 3n for every third element)') 19 | default: 20 | throw new Error('DataField error') 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/filter.js: -------------------------------------------------------------------------------- 1 | import { findProp } from './utils' 2 | 3 | function isGreater (el, selector, value) { 4 | let propValue = findProp(el, selector) 5 | if (Array.isArray(propValue)) propValue = propValue.length 6 | if (value instanceof Date) propValue = new Date(propValue) 7 | return propValue > value 8 | } 9 | 10 | function isGreaterOrEq (el, selector, value) { 11 | let propValue = findProp(el, selector) 12 | if (Array.isArray(propValue)) propValue = propValue.length 13 | if (value instanceof Date) propValue = new Date(propValue) 14 | return propValue >= value 15 | } 16 | 17 | function isLess (el, selector, value) { 18 | let propValue = findProp(el, selector) 19 | if (Array.isArray(propValue)) propValue = propValue.length 20 | if (value instanceof Date) propValue = new Date(propValue) 21 | return propValue < value 22 | } 23 | 24 | function isLessOrEq (el, selector, value) { 25 | let propValue = findProp(el, selector) 26 | if (Array.isArray(propValue)) propValue = propValue.length 27 | if (value instanceof Date) propValue = new Date(propValue) 28 | return propValue <= value 29 | } 30 | 31 | function isEq (el, selector, value) { 32 | let propValue = findProp(el, selector) 33 | if (Array.isArray(propValue)) propValue = propValue.length 34 | if (value instanceof Date) propValue = new Date(propValue) 35 | return value instanceof Date ? propValue.getTime() === value.getTime() : propValue === value 36 | } 37 | 38 | function isNotEq (el, selector, value) { 39 | let propValue = findProp(el, selector) 40 | if (Array.isArray(propValue)) propValue = propValue.length 41 | if (value instanceof Date) propValue = new Date(propValue) 42 | return value instanceof Date ? propValue.getTime() !== value.getTime() : propValue !== value 43 | } 44 | 45 | function isLike (el, selector) { 46 | return Boolean(findProp(el, selector)) 47 | } 48 | 49 | export { isGreater, isGreaterOrEq, isLess, isLessOrEq, isEq, isNotEq, isLike } 50 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export function findProp (el, prop) { 2 | if (el.hasOwnProperty(prop)) return el[prop] 3 | return traverseKeys(el, prop) 4 | } 5 | 6 | export function randomTakes (len, num, collection = []) { 7 | const index = Math.floor(Math.random() * len) 8 | if (!collection.includes(index)) collection.push(index) 9 | return collection.length === num ? collection : randomTakes(len, num, collection) 10 | } 11 | 12 | function traverseKeys (obj, path, fallback) { 13 | if (!obj || typeof obj !== 'object') return typeof fallback === 'function' ? fallback() : fallback 14 | if (!path) return obj 15 | 16 | let o = Object.assign({}, obj) 17 | path = path.split('.') 18 | 19 | for (let i = 0; i < path.length; i++) { 20 | if (!o.hasOwnProperty(path[i])) return typeof fallback === 'function' ? fallback() : fallback 21 | o = o[path[i]] 22 | if (o !== Object(o) && i < path.length - 1) return typeof fallback === 'function' ? fallback() : fallback 23 | } 24 | 25 | return o 26 | } 27 | 28 | export function checkTypes (a, b) { 29 | if (typeof a !== typeof b) return false 30 | if (typeof a === 'object' && a instanceof Date && b instanceof Date) return true 31 | return typeof a === 'number' || typeof a === 'string' 32 | } 33 | -------------------------------------------------------------------------------- /test/comparison.test.js: -------------------------------------------------------------------------------- 1 | import DataField from '../src/datafield' 2 | import * as data from './data.json' 3 | 4 | const content = data.data 5 | 6 | let dataField = new DataField(content) 7 | 8 | /* global describe it expect beforeEach */ 9 | 10 | describe('Comparison', function () { 11 | beforeEach(function () { 12 | dataField = new DataField(content) 13 | }) 14 | describe('Equality', function () { 15 | it('should filter entries based on equality', function () { 16 | expect(dataField.where('age').eq(48).length).toEqual(2) 17 | }) 18 | 19 | it('should throw error if no selector is present', function () { 20 | expect(() => dataField.where().eq(48)).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 21 | }) 22 | 23 | it('should remove 1 item with matching date', function () { 24 | expect(dataField.where('registered').eq(new Date('Saturday, February 13, 2016 1:36 AM')).length).toEqual(1) 25 | }) 26 | 27 | it('should keep records with 3 friends', function () { 28 | expect(dataField.where('friends').eq(3).length).toEqual(96) 29 | }) 30 | }) 31 | 32 | describe('Inequality', function () { 33 | it('should filter entries based on inequality', function () { 34 | expect(dataField.where('age').not(48).length).toEqual(98) 35 | }) 36 | 37 | it('should should throw error if no selector is present', function () { 38 | expect(() => dataField.where().not()).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 39 | }) 40 | 41 | it('should remove 1 item with matching date', function () { 42 | expect(dataField.where('registered').not(new Date('may 1, 2015')).length).toEqual(99) 43 | }) 44 | 45 | it('should keep records with NOT 2 friends', function () { 46 | expect(dataField.where('friends').not(2).length).toEqual(99) 47 | }) 48 | }) 49 | 50 | describe('Greater', function () { 51 | it('should filter entries based on equality', function () { 52 | expect(dataField.where('age').gt(48).length).toEqual(42) 53 | }) 54 | 55 | it('should throw error if no selector is present', function () { 56 | expect(() => dataField.where().gt(48)).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 57 | }) 58 | 59 | it('should throw error if no value is present', function () { 60 | expect(() => dataField.where('age').gt()).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 61 | }) 62 | 63 | it('should filter by date', function () { 64 | expect(dataField.where('registered').gt(new Date('may 1, 2015')).length).toEqual(70) 65 | }) 66 | 67 | it('should keep records with any amount of friends (>0)', function () { 68 | expect(dataField.where('friends').gt(0).length).toEqual(98) 69 | }) 70 | }) 71 | 72 | describe('Greater-Equal', function () { 73 | it('should filter entries based on equality', function () { 74 | expect(dataField.where('age').gte(48).length).toEqual(44) 75 | }) 76 | 77 | it('should throw error if no selector is present', function () { 78 | expect(() => dataField.where().gte(48)).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 79 | }) 80 | 81 | it('should throw error if no value is present', function () { 82 | expect(() => dataField.where('age').gte()).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 83 | }) 84 | 85 | it('should filter by date', function () { 86 | expect(dataField.where('registered').gte(new Date('may 1, 2015')).length).toEqual(71) 87 | }) 88 | it('should keep records with 2 or more friends', function () { 89 | expect(dataField.where('friends').gte(2).length).toEqual(98) 90 | }) 91 | 92 | }) 93 | 94 | describe('Less', function () { 95 | it('should filter entries based on equality', function () { 96 | expect(dataField.where('age').lt(48).length).toEqual(56) 97 | }) 98 | 99 | it('should return unchanged dataset if no selector is present', function () { 100 | expect(() => dataField.where().lt(48)).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 101 | }) 102 | 103 | it('should should throw error if no value is present', function () { 104 | expect(() => dataField.where('age').lt()).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 105 | }) 106 | 107 | it('should filter by date', function () { 108 | expect(dataField.where('registered').lt(new Date('may 1, 2015')).length).toEqual(29) 109 | }) 110 | 111 | it('should keep records with less then 3 friends', function () { 112 | expect(dataField.where('friends').lt(3).length).toEqual(3) 113 | }) 114 | 115 | }) 116 | 117 | describe('Less-Equal', function () { 118 | it('should filter entries based on equality', function () { 119 | expect(dataField.where('age').lte(48).length).toEqual(58) 120 | }) 121 | 122 | it('should should throw error if no selector is present', function () { 123 | expect(() => dataField.where().lte(48)).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 124 | }) 125 | 126 | it('should throw Error if no value is present', function () { 127 | expect(() => dataField.where('age').lte()).toThrow('DataField selector or value not specified, use .where(selector) and check method arguments') 128 | }) 129 | 130 | it('should filter by date', function () { 131 | expect(dataField.where('registered').lte(new Date('may 1, 2015')).length).toEqual(30) 132 | }) 133 | 134 | it('should keep records with 2 or less friends', function () { 135 | expect(dataField.where('friends').lte(2).length).toEqual(3) 136 | }) 137 | }) 138 | 139 | describe('Boolean filters', function () { 140 | it('should leave only the active accounts', function () { 141 | expect(dataField.where('isActive').isTruthy().length).toEqual(48) 142 | }) 143 | 144 | it('should leave only the inactive accounts', function () { 145 | expect(dataField.where('isActive').isFalsy().length).toEqual(52) 146 | }) 147 | 148 | }) 149 | }) 150 | -------------------------------------------------------------------------------- /test/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "_id": "5b420ae94fe6464ff91f5de8", 5 | "index": 0, 6 | "guid": "871eebf0-9983-4eb5-a0b5-59372a2fbecd", 7 | "isActive": true, 8 | "balance": "$1,268.06", 9 | "age": 41, 10 | "name": { 11 | "first": "Pearlie", 12 | "last": "Osborne" 13 | }, 14 | "company": "PIVITOL", 15 | "email": "pearlie.osborne@pivitol.net", 16 | "phone": "+1 (992) 418-2307", 17 | "address": "190 River Street, Spelter, Tennessee, 1088", 18 | "registered": "Monday, April 18, 2016 7:35 AM", 19 | "tags": [ 20 | "ad", 21 | "magna", 22 | "aliqua" 23 | ], 24 | "friends": [ 25 | { 26 | "id": 0, 27 | "name": "Whitney Snow" 28 | }, 29 | { 30 | "id": 1, 31 | "name": "Garza Hernandez" 32 | }, 33 | { 34 | "id": 2, 35 | "name": "Lourdes Conley" 36 | } 37 | ] 38 | }, 39 | { 40 | "_id": "5b420ae9f71b2f0e078b1016", 41 | "index": 1, 42 | "guid": "eae5f954-3972-4911-a0b8-bdd8e8220c47", 43 | "isActive": false, 44 | "balance": "$2,172.67", 45 | "age": 49, 46 | "name": { 47 | "last": "Franklin" 48 | }, 49 | "company": "SUREMAX", 50 | "email": "ashley.franklin@suremax.com", 51 | "phone": "+1 (944) 456-2798", 52 | "address": "726 Eldert Street, Interlochen, Delaware, 7519", 53 | "registered": "Monday, April 10, 2017 7:22 AM", 54 | "tags": [ 55 | "tempor", 56 | "excepteur", 57 | "ex" 58 | ], 59 | "friends": [] 60 | }, 61 | { 62 | "_id": "5b420ae993b405f6d5e9eaca", 63 | "index": 2, 64 | "guid": "199f77bf-58b1-474d-9f6d-38046a7c55a3", 65 | "isActive": false, 66 | "balance": "$3,823.04", 67 | "age": 30, 68 | "name": { 69 | "first": null, 70 | "last": "Brewer" 71 | }, 72 | "company": "INTERFIND", 73 | "email": "bernadette.brewer@interfind.me", 74 | "phone": "+1 (809) 548-2254", 75 | "address": "999 Division Avenue, Templeton, California, 5645", 76 | "registered": "Monday, July 6, 2015 4:52 AM", 77 | "tags": [ 78 | "eu", 79 | "nisi", 80 | "cillum" 81 | ], 82 | "friends":null 83 | }, 84 | { 85 | "_id": "5b420ae976dc28978caa75c6", 86 | "index": 3, 87 | "guid": "10a52d72-f1b8-4a95-9a78-1f8b7cbd9fc8", 88 | "isActive": true, 89 | "balance": "$3,934.23", 90 | "age": "24", 91 | "name": { 92 | "first": "Tamika", 93 | "last": "Ramirez" 94 | }, 95 | "company": "CORECOM", 96 | "email": "tamika.ramirez@corecom.tv", 97 | "phone": "+1 (951) 567-2309", 98 | "address": "325 Brightwater Court, Thatcher, Kentucky, 2274", 99 | "registered": "Monday, July 17, 2017 4:08 PM", 100 | "tags": [ 101 | "irure", 102 | "ad", 103 | "consectetur" 104 | ], 105 | "friends": [ 106 | { 107 | "id": 0, 108 | "name": "Wilder Harrison" 109 | }, 110 | { 111 | "id": 2, 112 | "name": "Ola Wright" 113 | } 114 | ] 115 | }, 116 | { 117 | "_id": "5b420ae9caf1b9dba99bbb94", 118 | "index": 4, 119 | "guid": "76252ebd-0ae5-4d0b-8eb2-0d5bf8a00339", 120 | "isActive": false, 121 | "balance": "$3,682.73", 122 | "age": 48, 123 | "name": { 124 | "first": "Danielle", 125 | "last": "Washington" 126 | }, 127 | "company": "ORBAXTER", 128 | "email": "danielle.washington@orbaxter.name", 129 | "phone": "+1 (965) 520-3535", 130 | "address": "219 Railroad Avenue, Walland, North Dakota, 9209", 131 | "registered": "Thursday, October 23, 2014 4:36 PM", 132 | "tags": [ 133 | "velit", 134 | "sint", 135 | "cillum" 136 | ], 137 | "friends": [ 138 | { 139 | "id": 0, 140 | "name": "Tia Alexander" 141 | }, 142 | { 143 | "id": 1, 144 | "name": "Vanessa Adkins" 145 | }, 146 | { 147 | "id": 2, 148 | "name": "Jill Bentley" 149 | } 150 | ] 151 | }, 152 | { 153 | "_id": "5b420ae9a547cea8f296c18e", 154 | "index": 5, 155 | "guid": "30f515d5-6ac0-40bb-9fe2-59cd8d560471", 156 | "isActive": false, 157 | "balance": "$1,410.68", 158 | "age": 45, 159 | "name": { 160 | "first": "Ballard", 161 | "last": "Bartlett" 162 | }, 163 | "company": "FANGOLD", 164 | "email": "ballard.bartlett@fangold.co.uk", 165 | "phone": "+1 (916) 574-3408", 166 | "address": "600 Cleveland Street, Santel, Pennsylvania, 9454", 167 | "registered": "Wednesday, September 10, 2014 4:06 AM", 168 | "tags": [ 169 | "fugiat", 170 | "ut", 171 | "mollit" 172 | ], 173 | "friends": [ 174 | { 175 | "id": 0, 176 | "name": "Kristine Hurley" 177 | }, 178 | { 179 | "id": 1, 180 | "name": "Annie Dejesus" 181 | }, 182 | { 183 | "id": 2, 184 | "name": "Christian Mcleod" 185 | } 186 | ] 187 | }, 188 | { 189 | "_id": "5b420ae92c7754a076df0f3b", 190 | "index": 6, 191 | "guid": "37921b7d-2ec8-4243-8d38-843aedc19d43", 192 | "isActive": false, 193 | "balance": "$2,246.96", 194 | "age": 38, 195 | "name": { 196 | "first": "Mack", 197 | "last": "Hutchinson" 198 | }, 199 | "company": "BOLAX", 200 | "email": "mack.hutchinson@bolax.biz", 201 | "phone": "+1 (931) 407-2270", 202 | "address": "976 Fulton Street, Leeper, Washington, 360", 203 | "registered": "Saturday, July 8, 2017 5:04 AM", 204 | "tags": [ 205 | "duis", 206 | "qui", 207 | "nulla" 208 | ], 209 | "friends": [ 210 | { 211 | "id": 0, 212 | "name": "Ester Kline" 213 | }, 214 | { 215 | "id": 1, 216 | "name": "Aguilar Potter" 217 | }, 218 | { 219 | "id": 2, 220 | "name": "Jaime Bush" 221 | } 222 | ] 223 | }, 224 | { 225 | "_id": "5b420ae907955f3d6641d423", 226 | "index": 7, 227 | "guid": "e31533f0-cce6-4971-bb76-c1a8c6b77025", 228 | "isActive": true, 229 | "balance": "$3,525.84", 230 | "age": 57, 231 | "name": { 232 | "first": "Ayala", 233 | "last": "Massey" 234 | }, 235 | "company": "ORBIFLEX", 236 | "email": "ayala.massey@orbiflex.org", 237 | "phone": "+1 (838) 469-2383", 238 | "address": "593 Highland Place, Topaz, Montana, 1614", 239 | "registered": "Thursday, September 10, 2015 3:20 PM", 240 | "tags": [ 241 | "magna", 242 | "nostrud", 243 | "irure" 244 | ], 245 | "friends": [ 246 | { 247 | "id": 0, 248 | "name": "Kemp Montoya" 249 | }, 250 | { 251 | "id": 1, 252 | "name": "England Wolf" 253 | }, 254 | { 255 | "id": 2, 256 | "name": "Eva Mcintyre" 257 | } 258 | ] 259 | }, 260 | { 261 | "_id": "5b420ae9f6e498d9a88add98", 262 | "index": 8, 263 | "guid": "29fc629a-ca7d-4fbb-a892-75a816dbd0bc", 264 | "isActive": false, 265 | "balance": "$2,459.42", 266 | "age": 56, 267 | "name": { 268 | "first": "Anna", 269 | "last": "Skinner" 270 | }, 271 | "company": "EXTRAWEAR", 272 | "email": "anna.skinner@extrawear.io", 273 | "phone": "+1 (853) 547-2731", 274 | "address": "576 Oriental Boulevard, Bentonville, Alaska, 8071", 275 | "registered": "Monday, May 11, 2015 12:56 AM", 276 | "tags": [ 277 | "adipisicing", 278 | "Lorem", 279 | "commodo" 280 | ], 281 | "friends": [ 282 | { 283 | "id": 0, 284 | "name": "Rowena Wilcox" 285 | }, 286 | { 287 | "id": 1, 288 | "name": "Luisa Fitzgerald" 289 | }, 290 | { 291 | "id": 2, 292 | "name": "Kristina Lawson" 293 | } 294 | ] 295 | }, 296 | { 297 | "_id": "5b420ae9f57b6c74c9552705", 298 | "index": 9, 299 | "guid": "430648a2-0e0f-43ca-a663-4cea26b32a05", 300 | "isActive": true, 301 | "balance": "$3,913.96", 302 | "age": 41, 303 | "name": { 304 | "first": "Blackwell", 305 | "last": "Hunter" 306 | }, 307 | "company": "CINASTER", 308 | "email": "blackwell.hunter@cinaster.us", 309 | "phone": "+1 (866) 482-2284", 310 | "address": "663 Fane Court, Hebron, Nebraska, 7162", 311 | "registered": "Monday, December 12, 2016 4:22 PM", 312 | "tags": [ 313 | "nostrud", 314 | "minim", 315 | "magna" 316 | ], 317 | "friends": [ 318 | { 319 | "id": 0, 320 | "name": "Chris Dawson" 321 | }, 322 | { 323 | "id": 1, 324 | "name": "Carpenter Barry" 325 | }, 326 | { 327 | "id": 2, 328 | "name": "Barr Winters" 329 | } 330 | ] 331 | }, 332 | { 333 | "_id": "5b420ae9521a27930f8ac266", 334 | "index": 10, 335 | "guid": "6b6c999a-6163-4ac0-ab54-10964b66efd5", 336 | "isActive": false, 337 | "balance": "$2,875.71", 338 | "age": 65, 339 | "name": { 340 | "first": "Bradley", 341 | "last": "Mcknight" 342 | }, 343 | "company": "XUMONK", 344 | "email": "bradley.mcknight@xumonk.ca", 345 | "phone": "+1 (855) 567-3563", 346 | "address": "891 Cumberland Walk, Riceville, Palau, 1331", 347 | "registered": "Saturday, December 2, 2017 6:14 PM", 348 | "tags": [ 349 | "cupidatat", 350 | "laboris", 351 | "irure" 352 | ], 353 | "friends": [ 354 | { 355 | "id": 0, 356 | "name": "Melendez Callahan" 357 | }, 358 | { 359 | "id": 1, 360 | "name": "Lilly Burch" 361 | }, 362 | { 363 | "id": 2, 364 | "name": "Juarez Charles" 365 | } 366 | ] 367 | }, 368 | { 369 | "_id": "5b420ae9c450bc56a84addd9", 370 | "index": 11, 371 | "guid": "4310fe57-7f7a-48e0-9b73-30d24e594184", 372 | "isActive": false, 373 | "balance": "$2,348.11", 374 | "age": 25, 375 | "name": { 376 | "first": "David", 377 | "last": "Goff" 378 | }, 379 | "company": "LIMAGE", 380 | "email": "david.goff@limage.info", 381 | "phone": "+1 (839) 477-2273", 382 | "address": "368 Preston Court, Elfrida, Puerto Rico, 3957", 383 | "registered": "Monday, May 28, 2018 12:23 PM", 384 | "tags": [ 385 | "aliqua", 386 | "ullamco", 387 | "quis" 388 | ], 389 | "friends": [ 390 | { 391 | "id": 0, 392 | "name": "Dixon Head" 393 | }, 394 | { 395 | "id": 1, 396 | "name": "Best Mays" 397 | }, 398 | { 399 | "id": 2, 400 | "name": "Sally Chen" 401 | } 402 | ] 403 | }, 404 | { 405 | "_id": "5b420ae9a26ae1f460afdc37", 406 | "index": 12, 407 | "guid": "8b3fd651-bce4-4a9c-930f-7f2caafd61ac", 408 | "isActive": true, 409 | "balance": "$1,117.25", 410 | "age": 32, 411 | "name": { 412 | "first": "Tabitha", 413 | "last": "Hendricks" 414 | }, 415 | "company": "TECHADE", 416 | "email": "tabitha.hendricks@techade.net", 417 | "phone": "+1 (847) 567-3495", 418 | "address": "275 Middagh Street, Welda, Kansas, 2622", 419 | "registered": "Sunday, January 31, 2016 4:50 AM", 420 | "tags": [ 421 | "in", 422 | "ea", 423 | "laboris" 424 | ], 425 | "friends": [ 426 | { 427 | "id": 0, 428 | "name": "Ellis Hester" 429 | }, 430 | { 431 | "id": 1, 432 | "name": "Maura Bates" 433 | }, 434 | { 435 | "id": 2, 436 | "name": "Petty Stanton" 437 | } 438 | ] 439 | }, 440 | { 441 | "_id": "5b420ae944318cce0a0e89f0", 442 | "index": 13, 443 | "guid": "d3f35eaa-fcaf-4c32-99df-da8698598f64", 444 | "isActive": false, 445 | "balance": "$3,438.39", 446 | "age": 45, 447 | "name": { 448 | "first": "Little", 449 | "last": "Gates" 450 | }, 451 | "company": "ISOSPHERE", 452 | "email": "little.gates@isosphere.com", 453 | "phone": "+1 (979) 449-3122", 454 | "address": "155 Columbia Street, Watchtower, Missouri, 9670", 455 | "registered": "Wednesday, February 8, 2017 11:34 AM", 456 | "tags": [ 457 | "incididunt", 458 | "culpa", 459 | "ipsum" 460 | ], 461 | "friends": [ 462 | { 463 | "id": 0, 464 | "name": "Donna Moss" 465 | }, 466 | { 467 | "id": 1, 468 | "name": "Norton Chambers" 469 | }, 470 | { 471 | "id": 2, 472 | "name": "Marquita Petty" 473 | } 474 | ] 475 | }, 476 | { 477 | "_id": "5b420ae9ec076ccc9cc398ea", 478 | "index": 14, 479 | "guid": "cfb35ee7-64ab-4c32-b55b-2b5521dcd08a", 480 | "isActive": false, 481 | "balance": "$2,788.40", 482 | "age": 27, 483 | "name": { 484 | "first": "Vang", 485 | "last": "Hale" 486 | }, 487 | "company": "OTHERSIDE", 488 | "email": "vang.hale@otherside.me", 489 | "phone": "+1 (831) 539-3293", 490 | "address": "635 Jefferson Avenue, Cobbtown, Maine, 1013", 491 | "registered": "Friday, August 22, 2014 5:40 AM", 492 | "tags": [ 493 | "dolor", 494 | "id", 495 | "consectetur" 496 | ], 497 | "friends": [ 498 | { 499 | "id": 0, 500 | "name": "Vicki Duke" 501 | }, 502 | { 503 | "id": 1, 504 | "name": "Effie Bishop" 505 | }, 506 | { 507 | "id": 2, 508 | "name": "Kelsey Craft" 509 | } 510 | ] 511 | }, 512 | { 513 | "_id": "5b420ae939d806103c336c99", 514 | "index": 15, 515 | "guid": "05096063-c7b8-420c-8cfc-3e690d4fc186", 516 | "isActive": false, 517 | "balance": "$1,341.32", 518 | "age": 52, 519 | "name": { 520 | "first": "Candice", 521 | "last": "Langley" 522 | }, 523 | "company": "OMNIGOG", 524 | "email": "candice.langley@omnigog.tv", 525 | "phone": "+1 (807) 479-3584", 526 | "address": "401 Anchorage Place, Finzel, Michigan, 5235", 527 | "registered": "Saturday, October 18, 2014 6:24 AM", 528 | "tags": [ 529 | "officia", 530 | "sint", 531 | "adipisicing" 532 | ], 533 | "friends": [ 534 | { 535 | "id": 0, 536 | "name": "Gross Bryant" 537 | }, 538 | { 539 | "id": 1, 540 | "name": "Audra Prince" 541 | }, 542 | { 543 | "id": 2, 544 | "name": "Susie Blair" 545 | } 546 | ] 547 | }, 548 | { 549 | "_id": "5b420ae9a042c9d2000fdb6f", 550 | "index": 16, 551 | "guid": "9227a67e-f8a1-4ca3-a3d0-4058d0f7901d", 552 | "isActive": false, 553 | "balance": "$2,053.86", 554 | "age": 50, 555 | "name": { 556 | "first": "Cleo", 557 | "last": "Delgado" 558 | }, 559 | "company": "NURPLEX", 560 | "email": "cleo.delgado@nurplex.name", 561 | "phone": "+1 (993) 533-3913", 562 | "address": "971 Matthews Court, Roland, Maryland, 8640", 563 | "registered": "Tuesday, February 28, 2017 5:29 AM", 564 | "tags": [ 565 | "commodo", 566 | "laboris", 567 | "proident" 568 | ], 569 | "friends": [ 570 | { 571 | "id": 0, 572 | "name": "Eleanor Ayers" 573 | }, 574 | { 575 | "id": 1, 576 | "name": "Deann Todd" 577 | }, 578 | { 579 | "id": 2, 580 | "name": "Erickson Mcconnell" 581 | } 582 | ] 583 | }, 584 | { 585 | "_id": "5b420ae9b302e3fe33ff0b7c", 586 | "index": 17, 587 | "guid": "0eda4dc6-96ba-4e93-aada-965d40ec237f", 588 | "isActive": false, 589 | "balance": "$1,054.67", 590 | "age": 65, 591 | "name": { 592 | "first": "Dejesus", 593 | "last": "Sweeney" 594 | }, 595 | "company": "MATRIXITY", 596 | "email": "dejesus.sweeney@matrixity.co.uk", 597 | "phone": "+1 (855) 522-2653", 598 | "address": "571 Dare Court, Lynn, Guam, 5995", 599 | "registered": "Friday, January 10, 2014 11:12 PM", 600 | "tags": [ 601 | "exercitation", 602 | "est", 603 | "ex" 604 | ], 605 | "friends": [ 606 | { 607 | "id": 0, 608 | "name": "Head Navarro" 609 | }, 610 | { 611 | "id": 1, 612 | "name": "Young Brooks" 613 | }, 614 | { 615 | "id": 2, 616 | "name": "Dale Cummings" 617 | } 618 | ] 619 | }, 620 | { 621 | "_id": "5b420ae91fba6a6c2bb13bc3", 622 | "index": 18, 623 | "guid": "5c50ab3e-6931-40c7-8700-8a5370410505", 624 | "isActive": true, 625 | "balance": "$1,175.33", 626 | "age": 57, 627 | "name": { 628 | "first": "Sanford", 629 | "last": "Ortega" 630 | }, 631 | "company": "ZILODYNE", 632 | "email": "sanford.ortega@zilodyne.biz", 633 | "phone": "+1 (898) 525-2835", 634 | "address": "379 Arion Place, Neahkahnie, Virginia, 7269", 635 | "registered": "Friday, May 12, 2017 9:40 AM", 636 | "tags": [ 637 | "anim", 638 | "esse", 639 | "officia" 640 | ], 641 | "friends": [ 642 | { 643 | "id": 0, 644 | "name": "Woodward Blackwell" 645 | }, 646 | { 647 | "id": 1, 648 | "name": "Mooney Juarez" 649 | }, 650 | { 651 | "id": 2, 652 | "name": "Berger Wise" 653 | } 654 | ] 655 | }, 656 | { 657 | "_id": "5b420ae95db8eaf0e8a3eff2", 658 | "index": 19, 659 | "guid": "46869216-5882-407b-af58-bc3b922a6169", 660 | "isActive": true, 661 | "balance": "$3,433.15", 662 | "age": 20, 663 | "name": { 664 | "first": "Bennett", 665 | "last": "Richardson" 666 | }, 667 | "company": "BEZAL", 668 | "email": "bennett.richardson@bezal.org", 669 | "phone": "+1 (837) 591-2516", 670 | "address": "284 Bragg Court, Crawfordsville, Illinois, 1801", 671 | "registered": "Sunday, December 7, 2014 9:57 PM", 672 | "tags": [ 673 | "excepteur", 674 | "amet", 675 | "adipisicing" 676 | ], 677 | "friends": [ 678 | { 679 | "id": 0, 680 | "name": "Strong Macias" 681 | }, 682 | { 683 | "id": 1, 684 | "name": "Logan Morrison" 685 | }, 686 | { 687 | "id": 2, 688 | "name": "Rosalie Nieves" 689 | } 690 | ] 691 | }, 692 | { 693 | "_id": "5b420ae9521773dc4192166a", 694 | "index": 20, 695 | "guid": "75a2c350-e3dd-4912-8dc4-83372ccb420f", 696 | "isActive": true, 697 | "balance": "$2,631.20", 698 | "age": 61, 699 | "name": { 700 | "first": "Francis", 701 | "last": "Guthrie" 702 | }, 703 | "company": "PURIA", 704 | "email": "francis.guthrie@puria.io", 705 | "phone": "+1 (931) 402-3539", 706 | "address": "886 Hutchinson Court, Floris, Texas, 5830", 707 | "registered": "Saturday, November 14, 2015 8:05 PM", 708 | "tags": [ 709 | "nisi", 710 | "dolor", 711 | "ut" 712 | ], 713 | "friends": [ 714 | { 715 | "id": 0, 716 | "name": "Marva Gordon" 717 | }, 718 | { 719 | "id": 1, 720 | "name": "Bullock Burke" 721 | }, 722 | { 723 | "id": 2, 724 | "name": "Hodge Williamson" 725 | } 726 | ] 727 | }, 728 | { 729 | "_id": "5b420ae9882586ace5e3ddd2", 730 | "index": 21, 731 | "guid": "0c01ec89-84ea-492f-9349-f0722f7b375e", 732 | "isActive": false, 733 | "balance": "$1,739.37", 734 | "age": 62, 735 | "name": { 736 | "first": "Tanner", 737 | "last": "Holman" 738 | }, 739 | "company": "GROK", 740 | "email": "tanner.holman@grok.us", 741 | "phone": "+1 (910) 459-2053", 742 | "address": "135 Bokee Court, Riner, Iowa, 9584", 743 | "registered": "Sunday, March 25, 2018 5:15 PM", 744 | "tags": [ 745 | "excepteur", 746 | "incididunt", 747 | "anim" 748 | ], 749 | "friends": [ 750 | { 751 | "id": 0, 752 | "name": "Charles Sloan" 753 | }, 754 | { 755 | "id": 1, 756 | "name": "Benson Mullins" 757 | }, 758 | { 759 | "id": 2, 760 | "name": "Vincent Harmon" 761 | } 762 | ] 763 | }, 764 | { 765 | "_id": "5b420ae91bdfdd7b16c4c285", 766 | "index": 22, 767 | "guid": "8eb3566b-158d-4fe4-8e63-bd910ac00d9d", 768 | "isActive": true, 769 | "balance": "$2,804.10", 770 | "age": 56, 771 | "name": { 772 | "first": "Watts", 773 | "last": "Yates" 774 | }, 775 | "company": "PIGZART", 776 | "email": "watts.yates@pigzart.ca", 777 | "phone": "+1 (943) 452-3680", 778 | "address": "262 Anthony Street, Lindcove, Hawaii, 2458", 779 | "registered": "Sunday, February 7, 2016 3:56 PM", 780 | "tags": [ 781 | "proident", 782 | "aliquip", 783 | "velit" 784 | ], 785 | "friends": [ 786 | { 787 | "id": 0, 788 | "name": "Olsen Young" 789 | }, 790 | { 791 | "id": 1, 792 | "name": "Hardy Dean" 793 | }, 794 | { 795 | "id": 2, 796 | "name": "Lolita Fuller" 797 | } 798 | ] 799 | }, 800 | { 801 | "_id": "5b420ae93cdc614adadb79f7", 802 | "index": 23, 803 | "guid": "38cb3c41-b677-4d90-9559-a65ae5c97dd1", 804 | "isActive": true, 805 | "balance": "$1,169.21", 806 | "age": 35, 807 | "name": { 808 | "first": "Eloise", 809 | "last": "Torres" 810 | }, 811 | "company": "VICON", 812 | "email": "eloise.torres@vicon.info", 813 | "phone": "+1 (938) 411-3600", 814 | "address": "331 Sedgwick Place, Limestone, Mississippi, 9358", 815 | "registered": "Wednesday, February 15, 2017 4:05 AM", 816 | "tags": [ 817 | "eu", 818 | "adipisicing", 819 | "irure" 820 | ], 821 | "friends": [ 822 | { 823 | "id": 0, 824 | "name": "Chavez Dale" 825 | }, 826 | { 827 | "id": 1, 828 | "name": "Torres Steele" 829 | }, 830 | { 831 | "id": 2, 832 | "name": "Betty Smith" 833 | } 834 | ] 835 | }, 836 | { 837 | "_id": "5b420ae97cc76e768cb5128c", 838 | "index": 24, 839 | "guid": "6ac1d4c4-1cc6-4cab-bd55-bd6c8917b796", 840 | "isActive": true, 841 | "balance": "$1,566.33", 842 | "age": 63, 843 | "name": { 844 | "first": "Sarah", 845 | "last": "Kirkland" 846 | }, 847 | "company": "BEADZZA", 848 | "email": "sarah.kirkland@beadzza.net", 849 | "phone": "+1 (974) 443-2484", 850 | "address": "344 Bartlett Place, Beason, Oregon, 4053", 851 | "registered": "Sunday, October 18, 2015 4:29 PM", 852 | "tags": [ 853 | "sit", 854 | "nisi", 855 | "sint" 856 | ], 857 | "friends": [ 858 | { 859 | "id": 0, 860 | "name": "Janelle Jackson" 861 | }, 862 | { 863 | "id": 1, 864 | "name": "Adele Durham" 865 | }, 866 | { 867 | "id": 2, 868 | "name": "Sallie Sellers" 869 | } 870 | ] 871 | }, 872 | { 873 | "_id": "5b420ae9ef11f219e510c07d", 874 | "index": 25, 875 | "guid": "366f1b9b-554c-4d7d-b1d0-5009e774ea5b", 876 | "isActive": true, 877 | "balance": "$1,948.79", 878 | "age": 49, 879 | "name": { 880 | "first": "Aileen", 881 | "last": "George" 882 | }, 883 | "company": "VIRVA", 884 | "email": "aileen.george@virva.com", 885 | "phone": "+1 (827) 452-2875", 886 | "address": "800 Oceanview Avenue, Camino, Florida, 4329", 887 | "registered": "Saturday, July 23, 2016 7:57 AM", 888 | "tags": [ 889 | "veniam", 890 | "consectetur", 891 | "ut" 892 | ], 893 | "friends": [ 894 | { 895 | "id": 0, 896 | "name": "Freeman Rhodes" 897 | }, 898 | { 899 | "id": 1, 900 | "name": "Craig Silva" 901 | }, 902 | { 903 | "id": 2, 904 | "name": "Patty Frost" 905 | } 906 | ] 907 | }, 908 | { 909 | "_id": "5b420ae9046d695a9196761a", 910 | "index": 26, 911 | "guid": "bb248690-8879-4d40-b4d5-661b41dab94b", 912 | "isActive": false, 913 | "balance": "$1,741.75", 914 | "age": 63, 915 | "name": { 916 | "first": "Adeline", 917 | "last": "Dalton" 918 | }, 919 | "company": "DIGIAL", 920 | "email": "adeline.dalton@digial.me", 921 | "phone": "+1 (985) 515-2198", 922 | "address": "489 Atkins Avenue, Malo, New Hampshire, 8288", 923 | "registered": "Tuesday, August 25, 2015 6:12 PM", 924 | "tags": [ 925 | "non", 926 | "tempor", 927 | "eiusmod" 928 | ], 929 | "friends": [ 930 | { 931 | "id": 0, 932 | "name": "Selena Shelton" 933 | }, 934 | { 935 | "id": 1, 936 | "name": "Chandler Hinton" 937 | }, 938 | { 939 | "id": 2, 940 | "name": "Farrell Johnston" 941 | } 942 | ] 943 | }, 944 | { 945 | "_id": "5b420ae931bdaad285afe3d5", 946 | "index": 27, 947 | "guid": "0dc1f57c-b4c2-4761-9621-ea3962b6c796", 948 | "isActive": true, 949 | "balance": "$1,505.26", 950 | "age": 59, 951 | "name": { 952 | "first": "Hurley", 953 | "last": "Aguilar" 954 | }, 955 | "company": "OPTICON", 956 | "email": "hurley.aguilar@opticon.tv", 957 | "phone": "+1 (962) 446-3938", 958 | "address": "191 Midwood Street, Bentley, Vermont, 5777", 959 | "registered": "Monday, December 25, 2017 9:37 PM", 960 | "tags": [ 961 | "aliquip", 962 | "cillum", 963 | "labore" 964 | ], 965 | "friends": [ 966 | { 967 | "id": 0, 968 | "name": "Bass Wiley" 969 | }, 970 | { 971 | "id": 1, 972 | "name": "Cecile Matthews" 973 | }, 974 | { 975 | "id": 2, 976 | "name": "Crosby Mercer" 977 | } 978 | ] 979 | }, 980 | { 981 | "_id": "5b420ae9e5162cff3e90368a", 982 | "index": 28, 983 | "guid": "fdc37dde-578c-4b5f-87be-003f34df69eb", 984 | "isActive": true, 985 | "balance": "$2,450.68", 986 | "age": 40, 987 | "name": { 988 | "first": "Ruiz", 989 | "last": "Davidson" 990 | }, 991 | "company": "LEXICONDO", 992 | "email": "ruiz.davidson@lexicondo.name", 993 | "phone": "+1 (870) 465-3553", 994 | "address": "102 Driggs Avenue, Defiance, Massachusetts, 8037", 995 | "registered": "Wednesday, September 21, 2016 8:18 AM", 996 | "tags": [ 997 | "minim", 998 | "qui", 999 | "culpa" 1000 | ], 1001 | "friends": [ 1002 | { 1003 | "id": 0, 1004 | "name": "Rowe Odonnell" 1005 | }, 1006 | { 1007 | "id": 1, 1008 | "name": "Weaver Daniel" 1009 | }, 1010 | { 1011 | "id": 2, 1012 | "name": "Hines Sargent" 1013 | } 1014 | ] 1015 | }, 1016 | { 1017 | "_id": "5b420ae996acd38725035f4f", 1018 | "index": 29, 1019 | "guid": "c697cac4-1bb2-4b58-9a24-8dfc8347afb8", 1020 | "isActive": true, 1021 | "balance": "$1,844.59", 1022 | "age": 28, 1023 | "name": { 1024 | "first": "Knapp", 1025 | "last": "Mathis" 1026 | }, 1027 | "company": "CIPROMOX", 1028 | "email": "knapp.mathis@cipromox.co.uk", 1029 | "phone": "+1 (848) 437-2668", 1030 | "address": "140 Clymer Street, Chalfant, Indiana, 8850", 1031 | "registered": "Saturday, September 26, 2015 5:16 PM", 1032 | "tags": [ 1033 | "ex", 1034 | "quis", 1035 | "ea" 1036 | ], 1037 | "friends": [ 1038 | { 1039 | "id": 0, 1040 | "name": "Carmen Horn" 1041 | }, 1042 | { 1043 | "id": 1, 1044 | "name": "Lopez Santiago" 1045 | }, 1046 | { 1047 | "id": 2, 1048 | "name": "Gabriela Short" 1049 | } 1050 | ] 1051 | }, 1052 | { 1053 | "_id": "5b420ae9437a3bd54cb2e525", 1054 | "index": 30, 1055 | "guid": "e9d6e531-dcb1-46f0-bef7-6e4a00af145c", 1056 | "isActive": true, 1057 | "balance": "$3,046.86", 1058 | "age": 25, 1059 | "name": { 1060 | "first": "Dianna", 1061 | "last": "Gilbert" 1062 | }, 1063 | "company": "COMTOUR", 1064 | "email": "dianna.gilbert@comtour.biz", 1065 | "phone": "+1 (990) 555-3685", 1066 | "address": "752 Bath Avenue, Centerville, Wisconsin, 4532", 1067 | "registered": "Saturday, July 8, 2017 4:19 AM", 1068 | "tags": [ 1069 | "id", 1070 | "consequat", 1071 | "quis" 1072 | ], 1073 | "friends": [ 1074 | { 1075 | "id": 0, 1076 | "name": "Candy Gregory" 1077 | }, 1078 | { 1079 | "id": 1, 1080 | "name": "Catherine Cannon" 1081 | }, 1082 | { 1083 | "id": 2, 1084 | "name": "Leanna Porter" 1085 | } 1086 | ] 1087 | }, 1088 | { 1089 | "_id": "5b420ae9d1a8ceb62f1d3608", 1090 | "index": 31, 1091 | "guid": "f1e34392-148a-4503-a7a4-833dc70364c3", 1092 | "isActive": false, 1093 | "balance": "$2,573.91", 1094 | "age": 49, 1095 | "name": { 1096 | "first": "Day", 1097 | "last": "Christensen" 1098 | }, 1099 | "company": "EZENTIA", 1100 | "email": "day.christensen@ezentia.org", 1101 | "phone": "+1 (962) 589-2691", 1102 | "address": "964 Abbey Court, Jeff, Idaho, 4921", 1103 | "registered": "Sunday, April 17, 2016 12:00 PM", 1104 | "tags": [ 1105 | "quis", 1106 | "proident", 1107 | "enim" 1108 | ], 1109 | "friends": [ 1110 | { 1111 | "id": 0, 1112 | "name": "Johns Garrison" 1113 | }, 1114 | { 1115 | "id": 1, 1116 | "name": "Mckay Riddle" 1117 | }, 1118 | { 1119 | "id": 2, 1120 | "name": "Parker Logan" 1121 | } 1122 | ] 1123 | }, 1124 | { 1125 | "_id": "5b420ae9ddacad160a58f8c3", 1126 | "index": 32, 1127 | "guid": "c7b5d972-fe2f-408a-b5cb-5fd48130e471", 1128 | "isActive": false, 1129 | "balance": "$2,007.50", 1130 | "age": 28, 1131 | "name": { 1132 | "first": "Wendi", 1133 | "last": "Mcfarland" 1134 | }, 1135 | "company": "PHORMULA", 1136 | "email": "wendi.mcfarland@phormula.io", 1137 | "phone": "+1 (908) 544-2090", 1138 | "address": "180 Havens Place, Cutter, Arkansas, 1796", 1139 | "registered": "Tuesday, December 2, 2014 6:10 AM", 1140 | "tags": [ 1141 | "elit", 1142 | "consectetur", 1143 | "adipisicing" 1144 | ], 1145 | "friends": [ 1146 | { 1147 | "id": 0, 1148 | "name": "Wiley Hobbs" 1149 | }, 1150 | { 1151 | "id": 1, 1152 | "name": "Annmarie Mcintosh" 1153 | }, 1154 | { 1155 | "id": 2, 1156 | "name": "Elinor Gross" 1157 | } 1158 | ] 1159 | }, 1160 | { 1161 | "_id": "5b420ae9eb89bef9cea9bb3c", 1162 | "index": 33, 1163 | "guid": "750ff51d-3431-4dc6-b341-ce8d2c343bba", 1164 | "isActive": false, 1165 | "balance": "$2,027.04", 1166 | "age": 19, 1167 | "name": { 1168 | "first": "Moon", 1169 | "last": "Farrell" 1170 | }, 1171 | "company": "ISOTRACK", 1172 | "email": "moon.farrell@isotrack.us", 1173 | "phone": "+1 (951) 521-2273", 1174 | "address": "309 Louise Terrace, Cannondale, South Carolina, 4228", 1175 | "registered": "Sunday, January 5, 2014 10:18 AM", 1176 | "tags": [ 1177 | "cillum", 1178 | "commodo", 1179 | "tempor" 1180 | ], 1181 | "friends": [ 1182 | { 1183 | "id": 0, 1184 | "name": "Coffey Hodges" 1185 | }, 1186 | { 1187 | "id": 1, 1188 | "name": "Esther Bryan" 1189 | }, 1190 | { 1191 | "id": 2, 1192 | "name": "Trujillo Burnett" 1193 | } 1194 | ] 1195 | }, 1196 | { 1197 | "_id": "5b420ae9259f4edee66cb591", 1198 | "index": 34, 1199 | "guid": "2bf796f5-4b66-4abc-bf51-d1213efa83bc", 1200 | "isActive": false, 1201 | "balance": "$2,391.20", 1202 | "age": 44, 1203 | "name": { 1204 | "first": "Susanna", 1205 | "last": "Lowe" 1206 | }, 1207 | "company": "MUSIX", 1208 | "email": "susanna.lowe@musix.ca", 1209 | "phone": "+1 (886) 467-2813", 1210 | "address": "688 Montauk Avenue, Dunnavant, Nevada, 4302", 1211 | "registered": "Thursday, September 29, 2016 3:36 AM", 1212 | "tags": [ 1213 | "pariatur", 1214 | "ex", 1215 | "culpa" 1216 | ], 1217 | "friends": [ 1218 | { 1219 | "id": 0, 1220 | "name": "Robles Potts" 1221 | }, 1222 | { 1223 | "id": 1, 1224 | "name": "Carroll Lindsay" 1225 | }, 1226 | { 1227 | "id": 2, 1228 | "name": "Frye Meyer" 1229 | } 1230 | ] 1231 | }, 1232 | { 1233 | "_id": "5b420ae9bfa1e724f1a3ea32", 1234 | "index": 35, 1235 | "guid": "29b13e03-60c5-42b1-8f21-79379ff52372", 1236 | "isActive": false, 1237 | "balance": "$1,271.71", 1238 | "age": 35, 1239 | "name": { 1240 | "first": "Ina", 1241 | "last": "Mcgee" 1242 | }, 1243 | "company": "NSPIRE", 1244 | "email": "ina.mcgee@nspire.info", 1245 | "phone": "+1 (930) 527-2965", 1246 | "address": "505 Borinquen Pl, Yorklyn, District Of Columbia, 7377", 1247 | "registered": "Saturday, February 14, 2015 6:12 PM", 1248 | "tags": [ 1249 | "incididunt", 1250 | "labore", 1251 | "voluptate" 1252 | ], 1253 | "friends": [ 1254 | { 1255 | "id": 0, 1256 | "name": "Larsen Moreno" 1257 | }, 1258 | { 1259 | "id": 1, 1260 | "name": "Jennings West" 1261 | }, 1262 | { 1263 | "id": 2, 1264 | "name": "Shauna Roberts" 1265 | } 1266 | ] 1267 | }, 1268 | { 1269 | "_id": "5b420ae97b0d586f70c19fac", 1270 | "index": 36, 1271 | "guid": "1bd65a8c-998e-4e58-b160-9d82941bbccd", 1272 | "isActive": false, 1273 | "balance": "$3,978.83", 1274 | "age": 54, 1275 | "name": { 1276 | "first": "Cabrera", 1277 | "last": "Baird" 1278 | }, 1279 | "company": "CABLAM", 1280 | "email": "cabrera.baird@cablam.net", 1281 | "phone": "+1 (996) 546-2451", 1282 | "address": "791 Strong Place, Jessie, Utah, 1344", 1283 | "registered": "Monday, May 18, 2015 12:01 AM", 1284 | "tags": [ 1285 | "enim", 1286 | "amet", 1287 | "esse" 1288 | ], 1289 | "friends": [ 1290 | { 1291 | "id": 0, 1292 | "name": "Kimberly Byrd" 1293 | }, 1294 | { 1295 | "id": 1, 1296 | "name": "Mcdonald Quinn" 1297 | }, 1298 | { 1299 | "id": 2, 1300 | "name": "Kerri Freeman" 1301 | } 1302 | ] 1303 | }, 1304 | { 1305 | "_id": "5b420ae9404b6070c150ca72", 1306 | "index": 37, 1307 | "guid": "5fc5e6e2-e409-41af-8bc4-7b9f634f4b36", 1308 | "isActive": true, 1309 | "balance": "$1,200.89", 1310 | "age": 20, 1311 | "name": { 1312 | "first": "Blanche", 1313 | "last": "Noble" 1314 | }, 1315 | "company": "BEDDER", 1316 | "email": "blanche.noble@bedder.com", 1317 | "phone": "+1 (866) 480-2995", 1318 | "address": "567 Verona Place, Chelsea, Louisiana, 5934", 1319 | "registered": "Saturday, January 14, 2017 2:01 AM", 1320 | "tags": [ 1321 | "fugiat", 1322 | "culpa", 1323 | "veniam" 1324 | ], 1325 | "friends": [ 1326 | { 1327 | "id": 0, 1328 | "name": "Bradshaw Parsons" 1329 | }, 1330 | { 1331 | "id": 1, 1332 | "name": "Krista Jefferson" 1333 | }, 1334 | { 1335 | "id": 2, 1336 | "name": "Buckley Jennings" 1337 | } 1338 | ] 1339 | }, 1340 | { 1341 | "_id": "5b420ae967eb966d4c8d1a78", 1342 | "index": 38, 1343 | "guid": "d9bd8941-e85b-4da2-b498-c0856f8a35ee", 1344 | "isActive": true, 1345 | "balance": "$1,739.23", 1346 | "age": 24, 1347 | "name": { 1348 | "first": "Mccarty", 1349 | "last": "Terrell" 1350 | }, 1351 | "company": "OPTIQUE", 1352 | "email": "mccarty.terrell@optique.me", 1353 | "phone": "+1 (827) 567-3215", 1354 | "address": "977 Wyckoff Street, Kapowsin, Rhode Island, 6855", 1355 | "registered": "Monday, April 17, 2017 8:43 PM", 1356 | "tags": [ 1357 | "et", 1358 | "mollit", 1359 | "deserunt" 1360 | ], 1361 | "friends": [ 1362 | { 1363 | "id": 0, 1364 | "name": "Hattie Patel" 1365 | }, 1366 | { 1367 | "id": 1, 1368 | "name": "Bush Howell" 1369 | }, 1370 | { 1371 | "id": 2, 1372 | "name": "Calderon Good" 1373 | } 1374 | ] 1375 | }, 1376 | { 1377 | "_id": "5b420ae9dda5cad11f9b3f04", 1378 | "index": 39, 1379 | "guid": "c6a398cd-d71d-47be-b7a0-9aaef0f109ec", 1380 | "isActive": false, 1381 | "balance": "$3,509.31", 1382 | "age": 57, 1383 | "name": { 1384 | "first": "Lyons", 1385 | "last": "Pena" 1386 | }, 1387 | "company": "MAGNAFONE", 1388 | "email": "lyons.pena@magnafone.tv", 1389 | "phone": "+1 (877) 419-2690", 1390 | "address": "356 Melba Court, Brookfield, Marshall Islands, 2245", 1391 | "registered": "Monday, May 15, 2017 2:12 PM", 1392 | "tags": [ 1393 | "ea", 1394 | "qui", 1395 | "proident" 1396 | ], 1397 | "friends": [ 1398 | { 1399 | "id": 0, 1400 | "name": "Jeannie Lindsey" 1401 | }, 1402 | { 1403 | "id": 1, 1404 | "name": "Collier Decker" 1405 | }, 1406 | { 1407 | "id": 2, 1408 | "name": "Hallie Mcneil" 1409 | } 1410 | ] 1411 | }, 1412 | { 1413 | "_id": "5b420ae9752090d41d33c206", 1414 | "index": 40, 1415 | "guid": "c8ddc1c4-eb63-4b5c-9230-848671eccb48", 1416 | "isActive": false, 1417 | "balance": "$2,455.47", 1418 | "age": 34, 1419 | "name": { 1420 | "first": "Stevenson", 1421 | "last": "Hooper" 1422 | }, 1423 | "company": "ASSURITY", 1424 | "email": "stevenson.hooper@assurity.name", 1425 | "phone": "+1 (982) 447-3686", 1426 | "address": "769 Hancock Street, Grill, American Samoa, 4884", 1427 | "registered": "Wednesday, October 1, 2014 6:45 PM", 1428 | "tags": [ 1429 | "voluptate", 1430 | "Lorem", 1431 | "proident" 1432 | ], 1433 | "friends": [ 1434 | { 1435 | "id": 0, 1436 | "name": "Brandy Mercado" 1437 | }, 1438 | { 1439 | "id": 1, 1440 | "name": "Leach Villarreal" 1441 | }, 1442 | { 1443 | "id": 2, 1444 | "name": "Carter Middleton" 1445 | } 1446 | ] 1447 | }, 1448 | { 1449 | "_id": "5b420ae96edfc49ed79115bf", 1450 | "index": 41, 1451 | "guid": "d517ddad-072a-4fa5-929b-4d069d1655d2", 1452 | "isActive": false, 1453 | "balance": "$1,266.87", 1454 | "age": 27, 1455 | "name": { 1456 | "first": "Kramer", 1457 | "last": "Gill" 1458 | }, 1459 | "company": "EXPOSA", 1460 | "email": "kramer.gill@exposa.co.uk", 1461 | "phone": "+1 (854) 487-2514", 1462 | "address": "715 Kent Avenue, Ripley, Arizona, 6198", 1463 | "registered": "Monday, March 6, 2017 12:52 PM", 1464 | "tags": [ 1465 | "sit", 1466 | "reprehenderit", 1467 | "in" 1468 | ], 1469 | "friends": [ 1470 | { 1471 | "id": 0, 1472 | "name": "Corina Gilmore" 1473 | }, 1474 | { 1475 | "id": 1, 1476 | "name": "Gail Schneider" 1477 | }, 1478 | { 1479 | "id": 2, 1480 | "name": "Margery Henry" 1481 | } 1482 | ] 1483 | }, 1484 | { 1485 | "_id": "5b420ae93ccd3debcd1c8e4b", 1486 | "index": 42, 1487 | "guid": "eb7cd0d6-2716-4c10-bc28-69851a89b7fe", 1488 | "isActive": false, 1489 | "balance": "$3,707.61", 1490 | "age": 30, 1491 | "name": { 1492 | "first": "Carol", 1493 | "last": "Webster" 1494 | }, 1495 | "company": "PAPRIKUT", 1496 | "email": "carol.webster@paprikut.biz", 1497 | "phone": "+1 (837) 533-3318", 1498 | "address": "993 Grove Street, Newcastle, South Dakota, 2969", 1499 | "registered": "Saturday, June 9, 2018 10:15 PM", 1500 | "tags": [ 1501 | "quis", 1502 | "excepteur", 1503 | "et" 1504 | ], 1505 | "friends": [ 1506 | { 1507 | "id": 0, 1508 | "name": "Contreras Peck" 1509 | }, 1510 | { 1511 | "id": 1, 1512 | "name": "Sheryl Houston" 1513 | }, 1514 | { 1515 | "id": 2, 1516 | "name": "Conway Swanson" 1517 | } 1518 | ] 1519 | }, 1520 | { 1521 | "_id": "5b420ae9f15407cc0902c957", 1522 | "index": 43, 1523 | "guid": "e5f0e7cc-a64c-407e-82e0-ea92110bcf14", 1524 | "isActive": false, 1525 | "balance": "$2,561.74", 1526 | "age": 64, 1527 | "name": { 1528 | "first": "Kathrine", 1529 | "last": "Humphrey" 1530 | }, 1531 | "company": "COMCUBINE", 1532 | "email": "kathrine.humphrey@comcubine.org", 1533 | "phone": "+1 (853) 536-2127", 1534 | "address": "139 Gotham Avenue, Eggertsville, Georgia, 2929", 1535 | "registered": "Sunday, March 8, 2015 9:27 AM", 1536 | "tags": [ 1537 | "mollit", 1538 | "dolor", 1539 | "fugiat" 1540 | ], 1541 | "friends": [ 1542 | { 1543 | "id": 0, 1544 | "name": "Emily Davenport" 1545 | }, 1546 | { 1547 | "id": 1, 1548 | "name": "Wagner Owen" 1549 | }, 1550 | { 1551 | "id": 2, 1552 | "name": "Rodriquez Poole" 1553 | } 1554 | ] 1555 | }, 1556 | { 1557 | "_id": "5b420ae9067de222ea313079", 1558 | "index": 44, 1559 | "guid": "7f124ba0-4090-4db4-acdd-06826a26a1cf", 1560 | "isActive": true, 1561 | "balance": "$1,816.20", 1562 | "age": 65, 1563 | "name": { 1564 | "first": "Keri", 1565 | "last": "Obrien" 1566 | }, 1567 | "company": "DREAMIA", 1568 | "email": "keri.obrien@dreamia.io", 1569 | "phone": "+1 (960) 429-2584", 1570 | "address": "215 Batchelder Street, Ribera, Federated States Of Micronesia, 5709", 1571 | "registered": "Friday, July 14, 2017 4:49 AM", 1572 | "tags": [ 1573 | "ea", 1574 | "Lorem", 1575 | "ex" 1576 | ], 1577 | "friends": [ 1578 | { 1579 | "id": 0, 1580 | "name": "Sosa Forbes" 1581 | }, 1582 | { 1583 | "id": 1, 1584 | "name": "Pearl Bright" 1585 | }, 1586 | { 1587 | "id": 2, 1588 | "name": "Carrie Blake" 1589 | } 1590 | ] 1591 | }, 1592 | { 1593 | "_id": "5b420ae914d7daac6beaa53b", 1594 | "index": 45, 1595 | "guid": "24a485da-4cf0-4b1d-b413-a58f2cb2a1dd", 1596 | "isActive": true, 1597 | "balance": "$2,399.19", 1598 | "age": 29, 1599 | "name": { 1600 | "first": "Liza", 1601 | "last": "Marshall" 1602 | }, 1603 | "company": "BOILCAT", 1604 | "email": "liza.marshall@boilcat.us", 1605 | "phone": "+1 (809) 533-3855", 1606 | "address": "621 College Place, Wintersburg, New Mexico, 3076", 1607 | "registered": "Friday, August 12, 2016 1:44 PM", 1608 | "tags": [ 1609 | "ea", 1610 | "labore", 1611 | "cupidatat" 1612 | ], 1613 | "friends": [ 1614 | { 1615 | "id": 0, 1616 | "name": "Miles Aguirre" 1617 | }, 1618 | { 1619 | "id": 1, 1620 | "name": "Phyllis Harrell" 1621 | }, 1622 | { 1623 | "id": 2, 1624 | "name": "Martin Crawford" 1625 | } 1626 | ] 1627 | }, 1628 | { 1629 | "_id": "5b420ae9fd645c0834e130a5", 1630 | "index": 46, 1631 | "guid": "cc669560-0cb3-45a5-b933-0baf86a61601", 1632 | "isActive": true, 1633 | "balance": "$1,757.57", 1634 | "age": 50, 1635 | "name": { 1636 | "first": "Richards", 1637 | "last": "Anderson" 1638 | }, 1639 | "company": "IMPERIUM", 1640 | "email": "richards.anderson@imperium.ca", 1641 | "phone": "+1 (809) 531-3025", 1642 | "address": "994 Mill Lane, Summerset, Alabama, 7383", 1643 | "registered": "Wednesday, February 15, 2017 10:55 PM", 1644 | "tags": [ 1645 | "ea", 1646 | "Lorem", 1647 | "commodo" 1648 | ], 1649 | "friends": [ 1650 | { 1651 | "id": 0, 1652 | "name": "Elisa Cameron" 1653 | }, 1654 | { 1655 | "id": 1, 1656 | "name": "Mcneil Sexton" 1657 | }, 1658 | { 1659 | "id": 2, 1660 | "name": "Olga Shannon" 1661 | } 1662 | ] 1663 | }, 1664 | { 1665 | "_id": "5b420ae99f675449cafddfbc", 1666 | "index": 47, 1667 | "guid": "d3bb7e47-2ad0-4b77-9daf-77f01141a423", 1668 | "isActive": false, 1669 | "balance": "$1,266.75", 1670 | "age": 42, 1671 | "name": { 1672 | "first": "Rosie", 1673 | "last": "Berg" 1674 | }, 1675 | "company": "PRISMATIC", 1676 | "email": "rosie.berg@prismatic.info", 1677 | "phone": "+1 (980) 437-3440", 1678 | "address": "525 Livonia Avenue, Mapletown, New York, 1209", 1679 | "registered": "Sunday, April 3, 2016 9:18 PM", 1680 | "tags": [ 1681 | "Lorem", 1682 | "incididunt", 1683 | "proident" 1684 | ], 1685 | "friends": [ 1686 | { 1687 | "id": 0, 1688 | "name": "Renee Schroeder" 1689 | }, 1690 | { 1691 | "id": 1, 1692 | "name": "Naomi Mclean" 1693 | }, 1694 | { 1695 | "id": 2, 1696 | "name": "Good Shepherd" 1697 | } 1698 | ] 1699 | }, 1700 | { 1701 | "_id": "5b420ae9b53565bdc57ce09f", 1702 | "index": 48, 1703 | "guid": "4d245809-4307-4a8a-b408-ea3cac94b9c6", 1704 | "isActive": true, 1705 | "balance": "$1,703.83", 1706 | "age": 65, 1707 | "name": { 1708 | "first": "Louella", 1709 | "last": "Spears" 1710 | }, 1711 | "company": "ARCHITAX", 1712 | "email": "louella.spears@architax.net", 1713 | "phone": "+1 (885) 585-3109", 1714 | "address": "640 Macon Street, Trexlertown, Virgin Islands, 3172", 1715 | "registered": "Friday, August 28, 2015 3:47 AM", 1716 | "tags": [ 1717 | "commodo", 1718 | "ut", 1719 | "adipisicing" 1720 | ], 1721 | "friends": [ 1722 | { 1723 | "id": 0, 1724 | "name": "Foley Hartman" 1725 | }, 1726 | { 1727 | "id": 1, 1728 | "name": "Jerry Lynch" 1729 | }, 1730 | { 1731 | "id": 2, 1732 | "name": "Martinez Donovan" 1733 | } 1734 | ] 1735 | }, 1736 | { 1737 | "_id": "5b420ae9db9f9e16e007f930", 1738 | "index": 49, 1739 | "guid": "56df5bab-4bab-44d2-a8e2-e3591c8fc280", 1740 | "isActive": false, 1741 | "balance": "$2,001.58", 1742 | "age": 35, 1743 | "name": { 1744 | "first": "Henson", 1745 | "last": "Dudley" 1746 | }, 1747 | "company": "DEVILTOE", 1748 | "email": "henson.dudley@deviltoe.com", 1749 | "phone": "+1 (938) 581-2596", 1750 | "address": "866 Harrison Place, Fannett, Connecticut, 7669", 1751 | "registered": "Monday, July 24, 2017 5:30 PM", 1752 | "tags": [ 1753 | "fugiat", 1754 | "fugiat", 1755 | "irure" 1756 | ], 1757 | "friends": [ 1758 | { 1759 | "id": 0, 1760 | "name": "Deloris Hogan" 1761 | }, 1762 | { 1763 | "id": 1, 1764 | "name": "Roxie Harris" 1765 | }, 1766 | { 1767 | "id": 2, 1768 | "name": "Manuela Lynn" 1769 | } 1770 | ] 1771 | }, 1772 | { 1773 | "_id": "5b420ae90ece2fda4be84bca", 1774 | "index": 50, 1775 | "guid": "bc4b1ec5-346d-46a6-8794-beacc97177c3", 1776 | "isActive": false, 1777 | "balance": "$2,667.27", 1778 | "age": 49, 1779 | "name": { 1780 | "first": "Latisha", 1781 | "last": "Christian" 1782 | }, 1783 | "company": "MICROLUXE", 1784 | "email": "latisha.christian@microluxe.me", 1785 | "phone": "+1 (951) 579-3678", 1786 | "address": "158 Vanderbilt Avenue, Oceola, North Carolina, 9452", 1787 | "registered": "Wednesday, May 17, 2017 9:20 AM", 1788 | "tags": [ 1789 | "culpa", 1790 | "aute", 1791 | "laboris" 1792 | ], 1793 | "friends": [ 1794 | { 1795 | "id": 0, 1796 | "name": "Reeves Hoover" 1797 | }, 1798 | { 1799 | "id": 1, 1800 | "name": "Leila Nielsen" 1801 | }, 1802 | { 1803 | "id": 2, 1804 | "name": "Elvia Carroll" 1805 | } 1806 | ] 1807 | }, 1808 | { 1809 | "_id": "5b420ae95df65cb9322f5407", 1810 | "index": 51, 1811 | "guid": "a43a4f3c-efe7-43e1-8745-1233b92e0bd5", 1812 | "isActive": false, 1813 | "balance": "$1,497.26", 1814 | "age": 66, 1815 | "name": { 1816 | "first": "Rosalind", 1817 | "last": "Graham" 1818 | }, 1819 | "company": "COMTENT", 1820 | "email": "rosalind.graham@comtent.tv", 1821 | "phone": "+1 (890) 581-2355", 1822 | "address": "196 Oliver Street, Orin, New Jersey, 5091", 1823 | "registered": "Friday, August 25, 2017 7:39 PM", 1824 | "tags": [ 1825 | "laboris", 1826 | "ea", 1827 | "velit" 1828 | ], 1829 | "friends": [ 1830 | { 1831 | "id": 0, 1832 | "name": "Burch Valentine" 1833 | }, 1834 | { 1835 | "id": 1, 1836 | "name": "Louisa Frank" 1837 | }, 1838 | { 1839 | "id": 2, 1840 | "name": "Hunter Bender" 1841 | }, 1842 | { 1843 | "id": 3, 1844 | "name": "John Yoshi" 1845 | } 1846 | ] 1847 | }, 1848 | { 1849 | "_id": "5b420ae95bab899f5e6eba5c", 1850 | "index": 52, 1851 | "guid": "dcbc5e2d-9961-4f72-b6ed-a711488f31cf", 1852 | "isActive": false, 1853 | "balance": "$1,590.57", 1854 | "age": 44, 1855 | "name": { 1856 | "first": "Rochelle", 1857 | "last": "Becker" 1858 | }, 1859 | "company": "PARLEYNET", 1860 | "email": "rochelle.becker@parleynet.name", 1861 | "phone": "+1 (910) 486-3922", 1862 | "address": "834 Hull Street, Sunbury, Ohio, 1033", 1863 | "registered": "Saturday, February 13, 2016 1:36 AM", 1864 | "tags": [ 1865 | "ipsum", 1866 | "commodo", 1867 | "ex" 1868 | ], 1869 | "friends": [ 1870 | { 1871 | "id": 0, 1872 | "name": "Claire Witt" 1873 | }, 1874 | { 1875 | "id": 1, 1876 | "name": "Briggs Whitley" 1877 | }, 1878 | { 1879 | "id": 2, 1880 | "name": "Geneva Ellis" 1881 | } 1882 | ] 1883 | }, 1884 | { 1885 | "_id": "5b420ae95d998ee0b117b90d", 1886 | "index": 53, 1887 | "guid": "a8d5ea6c-2198-4b95-86a7-9062fc596958", 1888 | "isActive": true, 1889 | "balance": "$3,314.67", 1890 | "age": 57, 1891 | "name": { 1892 | "first": "Sweet", 1893 | "last": "Stewart" 1894 | }, 1895 | "company": "PERKLE", 1896 | "email": "sweet.stewart@perkle.co.uk", 1897 | "phone": "+1 (935) 468-3626", 1898 | "address": "334 Douglass Street, Tilden, Wyoming, 7437", 1899 | "registered": "Monday, March 10, 2014 10:00 AM", 1900 | "tags": [ 1901 | "sit", 1902 | "consectetur", 1903 | "ullamco" 1904 | ], 1905 | "friends": [ 1906 | { 1907 | "id": 0, 1908 | "name": "Etta Glover" 1909 | }, 1910 | { 1911 | "id": 1, 1912 | "name": "Kathy Dotson" 1913 | }, 1914 | { 1915 | "id": 2, 1916 | "name": "Leon Mcfadden" 1917 | } 1918 | ] 1919 | }, 1920 | { 1921 | "_id": "5b420ae9feaa7ec0f325a351", 1922 | "index": 54, 1923 | "guid": "ed4bf676-c213-4a52-aef2-389bc8984fc1", 1924 | "isActive": false, 1925 | "balance": "$1,088.38", 1926 | "age": 47, 1927 | "name": { 1928 | "first": "Earlene", 1929 | "last": "Clemons" 1930 | }, 1931 | "company": "VIXO", 1932 | "email": "earlene.clemons@vixo.biz", 1933 | "phone": "+1 (993) 569-2281", 1934 | "address": "317 Kingston Avenue, Johnsonburg, Northern Mariana Islands, 9621", 1935 | "registered": "Saturday, January 21, 2017 8:51 AM", 1936 | "tags": [ 1937 | "velit", 1938 | "proident", 1939 | "excepteur" 1940 | ], 1941 | "friends": [ 1942 | { 1943 | "id": 0, 1944 | "name": "Evangeline Benton" 1945 | }, 1946 | { 1947 | "id": 1, 1948 | "name": "Barbra Nash" 1949 | }, 1950 | { 1951 | "id": 2, 1952 | "name": "Camille Mccormick" 1953 | } 1954 | ] 1955 | }, 1956 | { 1957 | "_id": "5b420ae91e017d5af88e02e1", 1958 | "index": 55, 1959 | "guid": "7ab6ed7c-a036-4224-91aa-d03f4c035a5e", 1960 | "isActive": false, 1961 | "balance": "$3,025.25", 1962 | "age": 20, 1963 | "name": { 1964 | "first": "Georgia", 1965 | "last": "Glenn" 1966 | }, 1967 | "company": "RENOVIZE", 1968 | "email": "georgia.glenn@renovize.org", 1969 | "phone": "+1 (990) 434-3763", 1970 | "address": "432 Christopher Avenue, Freeburn, Minnesota, 8415", 1971 | "registered": "Thursday, August 28, 2014 9:18 PM", 1972 | "tags": [ 1973 | "quis", 1974 | "dolor", 1975 | "veniam" 1976 | ], 1977 | "friends": [ 1978 | { 1979 | "id": 0, 1980 | "name": "Bethany Barker" 1981 | }, 1982 | { 1983 | "id": 1, 1984 | "name": "Constance Garner" 1985 | }, 1986 | { 1987 | "id": 2, 1988 | "name": "Orr Best" 1989 | } 1990 | ] 1991 | }, 1992 | { 1993 | "_id": "5b420ae93714e8853959acc5", 1994 | "index": 56, 1995 | "guid": "7113c35c-9b09-453c-8f73-68e0a432c729", 1996 | "isActive": true, 1997 | "balance": "$1,014.33", 1998 | "age": 43, 1999 | "name": { 2000 | "first": "Cooley", 2001 | "last": "Alvarado" 2002 | }, 2003 | "company": "DADABASE", 2004 | "email": "cooley.alvarado@dadabase.io", 2005 | "phone": "+1 (956) 473-3050", 2006 | "address": "606 Sumpter Street, Conway, Colorado, 807", 2007 | "registered": "Monday, May 30, 2016 7:08 PM", 2008 | "tags": [ 2009 | "eiusmod", 2010 | "excepteur", 2011 | "elit" 2012 | ], 2013 | "friends": [ 2014 | { 2015 | "id": 0, 2016 | "name": "Esperanza Atkinson" 2017 | }, 2018 | { 2019 | "id": 1, 2020 | "name": "Amelia Foster" 2021 | }, 2022 | { 2023 | "id": 2, 2024 | "name": "Millie Ferrell" 2025 | } 2026 | ] 2027 | }, 2028 | { 2029 | "_id": "5b420ae964808ee1b035ee59", 2030 | "index": 57, 2031 | "guid": "42ea9b39-a004-4f55-ad27-aad42108570c", 2032 | "isActive": true, 2033 | "balance": "$1,630.14", 2034 | "age": 51, 2035 | "name": { 2036 | "first": "Laura", 2037 | "last": "Morgan" 2038 | }, 2039 | "company": "EXIAND", 2040 | "email": "laura.morgan@exiand.us", 2041 | "phone": "+1 (915) 535-3680", 2042 | "address": "671 Kenmore Terrace, Dawn, Oklahoma, 4267", 2043 | "registered": "Wednesday, September 24, 2014 12:24 PM", 2044 | "tags": [ 2045 | "ex", 2046 | "ut", 2047 | "proident" 2048 | ], 2049 | "friends": [ 2050 | { 2051 | "id": 0, 2052 | "name": "Gayle Justice" 2053 | }, 2054 | { 2055 | "id": 1, 2056 | "name": "Herring Snyder" 2057 | }, 2058 | { 2059 | "id": 2, 2060 | "name": "Roberson Kramer" 2061 | } 2062 | ] 2063 | }, 2064 | { 2065 | "_id": "5b420ae94c0a8956d29fece5", 2066 | "index": 58, 2067 | "guid": "c1992cfd-e24f-46ea-b49a-0b166af016cf", 2068 | "isActive": false, 2069 | "balance": "$2,560.13", 2070 | "age": 60, 2071 | "name": { 2072 | "first": "Klein", 2073 | "last": "Nichols" 2074 | }, 2075 | "company": "TALKOLA", 2076 | "email": "klein.nichols@talkola.ca", 2077 | "phone": "+1 (800) 589-2801", 2078 | "address": "180 Lee Avenue, Columbus, Tennessee, 6852", 2079 | "registered": "Tuesday, March 18, 2014 12:16 AM", 2080 | "tags": [ 2081 | "proident", 2082 | "laboris", 2083 | "ad" 2084 | ], 2085 | "friends": [ 2086 | { 2087 | "id": 0, 2088 | "name": "Mills Pruitt" 2089 | }, 2090 | { 2091 | "id": 1, 2092 | "name": "Ada Vincent" 2093 | }, 2094 | { 2095 | "id": 2, 2096 | "name": "Beverley Dillon" 2097 | } 2098 | ] 2099 | }, 2100 | { 2101 | "_id": "5b420ae98b8e3f42f7dd1505", 2102 | "index": 59, 2103 | "guid": "e821e547-934b-4098-839e-a4cd06e7e2a3", 2104 | "isActive": true, 2105 | "balance": "$3,017.28", 2106 | "age": 51, 2107 | "name": { 2108 | "first": "Bell", 2109 | "last": "Hopkins" 2110 | }, 2111 | "company": "COMVOY", 2112 | "email": "bell.hopkins@comvoy.info", 2113 | "phone": "+1 (965) 506-3204", 2114 | "address": "758 Berkeley Place, Berlin, Delaware, 9088", 2115 | "registered": "Sunday, December 10, 2017 12:28 AM", 2116 | "tags": [ 2117 | "enim", 2118 | "eu", 2119 | "proident" 2120 | ], 2121 | "friends": [ 2122 | { 2123 | "id": 0, 2124 | "name": "Jacquelyn Cherry" 2125 | }, 2126 | { 2127 | "id": 1, 2128 | "name": "Deena Alston" 2129 | }, 2130 | { 2131 | "id": 2, 2132 | "name": "Dona Sparks" 2133 | } 2134 | ] 2135 | }, 2136 | { 2137 | "_id": "5b420ae92e7cb63fef077a7e", 2138 | "index": 60, 2139 | "guid": "65772964-0623-43a8-a75f-65bb243526d4", 2140 | "isActive": true, 2141 | "balance": "$2,639.63", 2142 | "age": 62, 2143 | "name": { 2144 | "first": "Neal", 2145 | "last": "Hess" 2146 | }, 2147 | "company": "GORGANIC", 2148 | "email": "neal.hess@gorganic.net", 2149 | "phone": "+1 (847) 522-2505", 2150 | "address": "250 Prince Street, Norris, California, 6188", 2151 | "registered": "Thursday, March 20, 2014 7:44 PM", 2152 | "tags": [ 2153 | "culpa", 2154 | "occaecat", 2155 | "excepteur" 2156 | ], 2157 | "friends": [ 2158 | { 2159 | "id": 0, 2160 | "name": "Glenna Dixon" 2161 | }, 2162 | { 2163 | "id": 1, 2164 | "name": "Spears Austin" 2165 | }, 2166 | { 2167 | "id": 2, 2168 | "name": "Smith Roth" 2169 | } 2170 | ] 2171 | }, 2172 | { 2173 | "_id": "5b420ae91076188e89baa2de", 2174 | "index": 61, 2175 | "guid": "305ec972-6f67-41d9-a2eb-3ca7aedd6337", 2176 | "isActive": true, 2177 | "balance": "$3,772.60", 2178 | "age": 57, 2179 | "name": { 2180 | "first": "Ila", 2181 | "last": "Pickett" 2182 | }, 2183 | "company": "REMOTION", 2184 | "email": "ila.pickett@remotion.com", 2185 | "phone": "+1 (981) 599-3205", 2186 | "address": "607 Kent Street, Konterra, Kentucky, 6404", 2187 | "registered": "Monday, January 16, 2017 10:26 PM", 2188 | "tags": [ 2189 | "non", 2190 | "irure", 2191 | "est" 2192 | ], 2193 | "friends": [ 2194 | { 2195 | "id": 0, 2196 | "name": "Christine Chan" 2197 | }, 2198 | { 2199 | "id": 1, 2200 | "name": "Kaye Lamb" 2201 | }, 2202 | { 2203 | "id": 2, 2204 | "name": "Emerson Olsen" 2205 | } 2206 | ] 2207 | }, 2208 | { 2209 | "_id": "5b420ae9575e57d6696ea425", 2210 | "index": 62, 2211 | "guid": "ac6c215a-8722-4024-ac4d-c8d0d8710d50", 2212 | "isActive": true, 2213 | "balance": "$2,528.99", 2214 | "age": 45, 2215 | "name": { 2216 | "first": "Fleming", 2217 | "last": "Erickson" 2218 | }, 2219 | "company": "PYRAMAX", 2220 | "email": "fleming.erickson@pyramax.me", 2221 | "phone": "+1 (901) 451-3165", 2222 | "address": "177 Dobbin Street, Kohatk, North Dakota, 345", 2223 | "registered": "Wednesday, February 1, 2017 7:19 PM", 2224 | "tags": [ 2225 | "pariatur", 2226 | "cillum", 2227 | "proident" 2228 | ], 2229 | "friends": [ 2230 | { 2231 | "id": 0, 2232 | "name": "Haynes Bruce" 2233 | }, 2234 | { 2235 | "id": 1, 2236 | "name": "Morales Buchanan" 2237 | }, 2238 | { 2239 | "id": 2, 2240 | "name": "Mcintosh Holder" 2241 | } 2242 | ] 2243 | }, 2244 | { 2245 | "_id": "5b420ae9b096ac1a910d90fd", 2246 | "index": 63, 2247 | "guid": "648a25fe-6aae-443b-8d9e-34faaf2cc6eb", 2248 | "isActive": false, 2249 | "balance": "$3,835.64", 2250 | "age": 29, 2251 | "name": { 2252 | "first": "Shana", 2253 | "last": "Abbott" 2254 | }, 2255 | "company": "QUAILCOM", 2256 | "email": "shana.abbott@quailcom.tv", 2257 | "phone": "+1 (949) 443-2686", 2258 | "address": "950 Conover Street, Crucible, Pennsylvania, 7896", 2259 | "registered": "Monday, February 13, 2017 11:11 AM", 2260 | "tags": [ 2261 | "anim", 2262 | "et", 2263 | "aute" 2264 | ], 2265 | "friends": [ 2266 | { 2267 | "id": 0, 2268 | "name": "Estelle Wilkerson" 2269 | }, 2270 | { 2271 | "id": 1, 2272 | "name": "Lily Bradley" 2273 | }, 2274 | { 2275 | "id": 2, 2276 | "name": "Elsie Blackburn" 2277 | } 2278 | ] 2279 | }, 2280 | { 2281 | "_id": "5b420ae9f3d48036e6daebd0", 2282 | "index": 64, 2283 | "guid": "6e16b022-592d-49e0-bd62-5a46e5a359ac", 2284 | "isActive": false, 2285 | "balance": "$3,129.35", 2286 | "age": 28, 2287 | "name": { 2288 | "first": "Carole", 2289 | "last": "Mclaughlin" 2290 | }, 2291 | "company": "ISOLOGIA", 2292 | "email": "carole.mclaughlin@isologia.name", 2293 | "phone": "+1 (872) 418-2189", 2294 | "address": "903 Emerald Street, Gadsden, Washington, 9749", 2295 | "registered": "Monday, June 1, 2015 4:16 AM", 2296 | "tags": [ 2297 | "ea", 2298 | "est", 2299 | "nostrud" 2300 | ], 2301 | "friends": [ 2302 | { 2303 | "id": 0, 2304 | "name": "Robert Shaw" 2305 | }, 2306 | { 2307 | "id": 1, 2308 | "name": "Tasha Levy" 2309 | }, 2310 | { 2311 | "id": 2, 2312 | "name": "Lorrie Lloyd" 2313 | } 2314 | ] 2315 | }, 2316 | { 2317 | "_id": "5b420ae954def88dffc14a79", 2318 | "index": 65, 2319 | "guid": "edcab93f-533b-42dd-8cd3-790ad3d3defd", 2320 | "isActive": false, 2321 | "balance": "$2,660.44", 2322 | "age": 43, 2323 | "name": { 2324 | "first": "Queen", 2325 | "last": "Mccarthy" 2326 | }, 2327 | "company": "WAAB", 2328 | "email": "queen.mccarthy@waab.co.uk", 2329 | "phone": "+1 (946) 519-3644", 2330 | "address": "878 Stone Avenue, Westphalia, Montana, 8520", 2331 | "registered": "Sunday, February 7, 2016 8:28 AM", 2332 | "tags": [ 2333 | "et", 2334 | "et", 2335 | "fugiat" 2336 | ], 2337 | "friends": [ 2338 | { 2339 | "id": 0, 2340 | "name": "Alta Miller" 2341 | }, 2342 | { 2343 | "id": 1, 2344 | "name": "Zelma Pennington" 2345 | }, 2346 | { 2347 | "id": 2, 2348 | "name": "Delores Bowen" 2349 | } 2350 | ] 2351 | }, 2352 | { 2353 | "_id": "5b420ae9559dcbb3b7103391", 2354 | "index": 66, 2355 | "guid": "e4d45d0c-b3a9-4971-9948-35ee1e8445c7", 2356 | "isActive": false, 2357 | "balance": "$3,382.65", 2358 | "age": 58, 2359 | "name": { 2360 | "first": "Daphne", 2361 | "last": "King" 2362 | }, 2363 | "company": "FROSNEX", 2364 | "email": "daphne.king@frosnex.biz", 2365 | "phone": "+1 (993) 495-2109", 2366 | "address": "696 Linden Boulevard, Otranto, Alaska, 8976", 2367 | "registered": "Saturday, January 3, 2015 2:07 PM", 2368 | "tags": [ 2369 | "anim", 2370 | "Lorem", 2371 | "laboris" 2372 | ], 2373 | "friends": [ 2374 | { 2375 | "id": 0, 2376 | "name": "Sheppard Cervantes" 2377 | }, 2378 | { 2379 | "id": 1, 2380 | "name": "Chan Mayer" 2381 | }, 2382 | { 2383 | "id": 2, 2384 | "name": "Dyer Green" 2385 | } 2386 | ] 2387 | }, 2388 | { 2389 | "_id": "5b420ae99eb70b7bc8fd6d45", 2390 | "index": 67, 2391 | "guid": "320e3ae7-6106-48f2-a897-400a98a97cee", 2392 | "isActive": true, 2393 | "balance": "$1,180.39", 2394 | "age": 66, 2395 | "name": { 2396 | "first": "Carla", 2397 | "last": "Simmons" 2398 | }, 2399 | "company": "BUZZOPIA", 2400 | "email": "carla.simmons@buzzopia.org", 2401 | "phone": "+1 (815) 505-3526", 2402 | "address": "841 Amber Street, Kenmar, Nebraska, 1200", 2403 | "registered": "Wednesday, April 1, 2015 8:59 AM", 2404 | "tags": [ 2405 | "magna", 2406 | "anim", 2407 | "aliquip" 2408 | ], 2409 | "friends": [ 2410 | { 2411 | "id": 0, 2412 | "name": "Shawn Bullock" 2413 | }, 2414 | { 2415 | "id": 1, 2416 | "name": "Edwina Sanders" 2417 | }, 2418 | { 2419 | "id": 2, 2420 | "name": "Savage Hines" 2421 | } 2422 | ] 2423 | }, 2424 | { 2425 | "_id": "5b420ae94649f7d46f9e2f92", 2426 | "index": 68, 2427 | "guid": "521dacef-a96e-4caa-b19b-11c6bdf047df", 2428 | "isActive": false, 2429 | "balance": "$3,267.35", 2430 | "age": 44, 2431 | "name": { 2432 | "first": "Sharp", 2433 | "last": "Rowland" 2434 | }, 2435 | "company": "JOVIOLD", 2436 | "email": "sharp.rowland@joviold.io", 2437 | "phone": "+1 (865) 428-2743", 2438 | "address": "718 Hampton Place, Kingstowne, Palau, 3878", 2439 | "registered": "Friday, March 7, 2014 4:45 AM", 2440 | "tags": [ 2441 | "mollit", 2442 | "quis", 2443 | "consectetur" 2444 | ], 2445 | "friends": [ 2446 | { 2447 | "id": 0, 2448 | "name": "Joanna Cox" 2449 | }, 2450 | { 2451 | "id": 1, 2452 | "name": "Mcintyre Carson" 2453 | }, 2454 | { 2455 | "id": 2, 2456 | "name": "Mckinney Klein" 2457 | } 2458 | ] 2459 | }, 2460 | { 2461 | "_id": "5b420ae9dc30910d8d8bd705", 2462 | "index": 69, 2463 | "guid": "d4161fb6-65fd-4765-b0f9-6beb37b403bf", 2464 | "isActive": true, 2465 | "balance": "$2,410.88", 2466 | "age": 55, 2467 | "name": { 2468 | "first": "Andrews", 2469 | "last": "Robbins" 2470 | }, 2471 | "company": "AQUAFIRE", 2472 | "email": "andrews.robbins@aquafire.us", 2473 | "phone": "+1 (999) 406-2522", 2474 | "address": "724 Whitwell Place, Highland, Puerto Rico, 7239", 2475 | "registered": "Friday, September 8, 2017 11:01 PM", 2476 | "tags": [ 2477 | "sit", 2478 | "deserunt", 2479 | "aute" 2480 | ], 2481 | "friends": [ 2482 | { 2483 | "id": 0, 2484 | "name": "Tameka Duncan" 2485 | }, 2486 | { 2487 | "id": 1, 2488 | "name": "Olive Daugherty" 2489 | }, 2490 | { 2491 | "id": 2, 2492 | "name": "Clay Camacho" 2493 | } 2494 | ] 2495 | }, 2496 | { 2497 | "_id": "5b420ae9a754fa4b34709973", 2498 | "index": 70, 2499 | "guid": "90cc3a38-5e55-49c2-aa64-4006ab07f6f5", 2500 | "isActive": false, 2501 | "balance": "$2,861.36", 2502 | "age": 20, 2503 | "name": { 2504 | "first": "Wilcox", 2505 | "last": "Golden" 2506 | }, 2507 | "company": "INQUALA", 2508 | "email": "wilcox.golden@inquala.ca", 2509 | "phone": "+1 (983) 592-3153", 2510 | "address": "825 Hegeman Avenue, Troy, Kansas, 4832", 2511 | "registered": "Sunday, April 19, 2015 2:37 AM", 2512 | "tags": [ 2513 | "pariatur", 2514 | "proident", 2515 | "nulla" 2516 | ], 2517 | "friends": [ 2518 | { 2519 | "id": 0, 2520 | "name": "Rosemary Hughes" 2521 | }, 2522 | { 2523 | "id": 1, 2524 | "name": "Latasha Lowery" 2525 | }, 2526 | { 2527 | "id": 2, 2528 | "name": "Colon Hunt" 2529 | } 2530 | ] 2531 | }, 2532 | { 2533 | "_id": "5b420ae97c0c3050ec4c0f32", 2534 | "index": 71, 2535 | "guid": "ddc24538-b54e-4076-ac77-0a50ff7b39f5", 2536 | "isActive": true, 2537 | "balance": "$3,424.94", 2538 | "age": 27, 2539 | "name": { 2540 | "first": "Thelma", 2541 | "last": "Sykes" 2542 | }, 2543 | "company": "SEALOUD", 2544 | "email": "thelma.sykes@sealoud.info", 2545 | "phone": "+1 (805) 592-3179", 2546 | "address": "517 Glendale Court, Sattley, Missouri, 3222", 2547 | "registered": "Friday, September 25, 2015 9:15 PM", 2548 | "tags": [ 2549 | "dolor", 2550 | "ipsum", 2551 | "id" 2552 | ], 2553 | "friends": [ 2554 | { 2555 | "id": 0, 2556 | "name": "Agnes Welch" 2557 | }, 2558 | { 2559 | "id": 1, 2560 | "name": "Alexandria Lawrence" 2561 | }, 2562 | { 2563 | "id": 2, 2564 | "name": "Zimmerman Thornton" 2565 | } 2566 | ] 2567 | }, 2568 | { 2569 | "_id": "5b420ae9ce947dfa6cc54e48", 2570 | "index": 72, 2571 | "guid": "461d54ee-f755-4cf8-9b5a-a9c8a6d8d47d", 2572 | "isActive": true, 2573 | "balance": "$1,749.76", 2574 | "age": 64, 2575 | "name": { 2576 | "first": "Allison", 2577 | "last": "Gomez" 2578 | }, 2579 | "company": "COMVENE", 2580 | "email": "allison.gomez@comvene.net", 2581 | "phone": "+1 (907) 551-2317", 2582 | "address": "200 Vermont Court, Swartzville, Maine, 6756", 2583 | "registered": "Friday, August 15, 2014 8:28 AM", 2584 | "tags": [ 2585 | "in", 2586 | "amet", 2587 | "sunt" 2588 | ], 2589 | "friends": [ 2590 | { 2591 | "id": 0, 2592 | "name": "Kristen Cantrell" 2593 | }, 2594 | { 2595 | "id": 1, 2596 | "name": "Douglas Lane" 2597 | }, 2598 | { 2599 | "id": 2, 2600 | "name": "Massey Kim" 2601 | } 2602 | ] 2603 | }, 2604 | { 2605 | "_id": "5b420ae9377da31685ab0cfb", 2606 | "index": 73, 2607 | "guid": "bd97a5e2-1514-4cbc-a35d-a3fb0fa98b32", 2608 | "isActive": false, 2609 | "balance": "$2,950.63", 2610 | "age": 38, 2611 | "name": { 2612 | "first": "Reese", 2613 | "last": "Odom" 2614 | }, 2615 | "company": "KROG", 2616 | "email": "reese.odom@krog.com", 2617 | "phone": "+1 (824) 409-3494", 2618 | "address": "318 Murdock Court, Belvoir, Michigan, 3067", 2619 | "registered": "Saturday, June 7, 2014 1:12 PM", 2620 | "tags": [ 2621 | "consectetur", 2622 | "consequat", 2623 | "culpa" 2624 | ], 2625 | "friends": [ 2626 | { 2627 | "id": 0, 2628 | "name": "Gracie Holloway" 2629 | }, 2630 | { 2631 | "id": 1, 2632 | "name": "Angeline Guerrero" 2633 | }, 2634 | { 2635 | "id": 2, 2636 | "name": "Shaffer Dunn" 2637 | } 2638 | ] 2639 | }, 2640 | { 2641 | "_id": "5b420ae91666d83690043fa8", 2642 | "index": 74, 2643 | "guid": "c7a734a5-90ee-457f-a8c1-7dbc91e2823b", 2644 | "isActive": true, 2645 | "balance": "$1,260.74", 2646 | "age": 21, 2647 | "name": { 2648 | "first": "Houston", 2649 | "last": "Payne" 2650 | }, 2651 | "company": "VOLAX", 2652 | "email": "houston.payne@volax.me", 2653 | "phone": "+1 (948) 478-3076", 2654 | "address": "757 Victor Road, Oneida, Maryland, 8521", 2655 | "registered": "Monday, May 23, 2016 4:13 AM", 2656 | "tags": [ 2657 | "adipisicing", 2658 | "enim", 2659 | "laborum" 2660 | ], 2661 | "friends": [ 2662 | { 2663 | "id": 0, 2664 | "name": "Beard Whitaker" 2665 | }, 2666 | { 2667 | "id": 1, 2668 | "name": "Navarro Griffin" 2669 | }, 2670 | { 2671 | "id": 2, 2672 | "name": "Kerr Herrera" 2673 | } 2674 | ] 2675 | }, 2676 | { 2677 | "_id": "5b420ae9ee7d9280f4fa8c0d", 2678 | "index": 75, 2679 | "guid": "ab9d60a0-7cd2-4f0b-b6dd-bf69059e449c", 2680 | "isActive": true, 2681 | "balance": "$3,651.64", 2682 | "age": 25, 2683 | "name": { 2684 | "first": "Vargas", 2685 | "last": "Baldwin" 2686 | }, 2687 | "company": "ECOSYS", 2688 | "email": "vargas.baldwin@ecosys.tv", 2689 | "phone": "+1 (878) 435-3920", 2690 | "address": "148 Stillwell Place, Soham, Guam, 9510", 2691 | "registered": "Thursday, July 16, 2015 10:44 PM", 2692 | "tags": [ 2693 | "incididunt", 2694 | "in", 2695 | "tempor" 2696 | ], 2697 | "friends": [ 2698 | { 2699 | "id": 0, 2700 | "name": "Dana Cash" 2701 | }, 2702 | { 2703 | "id": 1, 2704 | "name": "Norma Ellison" 2705 | }, 2706 | { 2707 | "id": 2, 2708 | "name": "Mari Summers" 2709 | } 2710 | ] 2711 | }, 2712 | { 2713 | "_id": "5b420ae9bad1abfc653292e5", 2714 | "index": 76, 2715 | "guid": "9f9cd7de-9969-4b7a-a6ff-9e6e5ae2fafc", 2716 | "isActive": true, 2717 | "balance": "$2,074.02", 2718 | "age": 30, 2719 | "name": { 2720 | "first": "Kelley", 2721 | "last": "Dyer" 2722 | }, 2723 | "company": "APPLICA", 2724 | "email": "kelley.dyer@applica.name", 2725 | "phone": "+1 (983) 551-3458", 2726 | "address": "677 Hall Street, Crisman, Virginia, 4336", 2727 | "registered": "Wednesday, May 11, 2016 10:19 AM", 2728 | "tags": [ 2729 | "ipsum", 2730 | "officia", 2731 | "officia" 2732 | ], 2733 | "friends": [ 2734 | { 2735 | "id": 0, 2736 | "name": "Lesley Conner" 2737 | }, 2738 | { 2739 | "id": 1, 2740 | "name": "Roth Jarvis" 2741 | }, 2742 | { 2743 | "id": 2, 2744 | "name": "Bessie Soto" 2745 | } 2746 | ] 2747 | }, 2748 | { 2749 | "_id": "5b420ae9cc72fabfa918df51", 2750 | "index": 77, 2751 | "guid": "a14ebfee-f186-430f-a10f-09d587fdd82e", 2752 | "isActive": false, 2753 | "balance": "$1,901.17", 2754 | "age": 60, 2755 | "name": { 2756 | "first": "Velasquez", 2757 | "last": "Clark" 2758 | }, 2759 | "company": "ZENSUS", 2760 | "email": "velasquez.clark@zensus.co.uk", 2761 | "phone": "+1 (872) 487-3782", 2762 | "address": "923 Ryder Street, Deseret, Illinois, 2680", 2763 | "registered": "Thursday, October 26, 2017 7:43 PM", 2764 | "tags": [ 2765 | "esse", 2766 | "pariatur", 2767 | "reprehenderit" 2768 | ], 2769 | "friends": [ 2770 | { 2771 | "id": 0, 2772 | "name": "Sondra Henderson" 2773 | }, 2774 | { 2775 | "id": 1, 2776 | "name": "Judith Fernandez" 2777 | }, 2778 | { 2779 | "id": 2, 2780 | "name": "Daniel Williams" 2781 | } 2782 | ] 2783 | }, 2784 | { 2785 | "_id": "5b420ae94fa12a9c22db5766", 2786 | "index": 78, 2787 | "guid": "67ce56fa-ce53-4c28-9e0b-d8fffc30737b", 2788 | "isActive": true, 2789 | "balance": "$1,848.97", 2790 | "age": 20, 2791 | "name": { 2792 | "first": "Carey", 2793 | "last": "Burris" 2794 | }, 2795 | "company": "ANIVET", 2796 | "email": "carey.burris@anivet.biz", 2797 | "phone": "+1 (962) 573-2319", 2798 | "address": "727 Carlton Avenue, Montura, Texas, 8946", 2799 | "registered": "Friday, December 4, 2015 10:19 PM", 2800 | "tags": [ 2801 | "est", 2802 | "reprehenderit", 2803 | "veniam" 2804 | ], 2805 | "friends": [ 2806 | { 2807 | "id": 0, 2808 | "name": "Nancy Richard" 2809 | }, 2810 | { 2811 | "id": 1, 2812 | "name": "Mcpherson Banks" 2813 | }, 2814 | { 2815 | "id": 2, 2816 | "name": "Heather Norton" 2817 | } 2818 | ] 2819 | }, 2820 | { 2821 | "_id": "5b420ae9e62181732341cdc3", 2822 | "index": 79, 2823 | "guid": "68acbc0f-6cf9-442e-b220-7cc2bde8ba62", 2824 | "isActive": true, 2825 | "balance": "$2,285.64", 2826 | "age": 59, 2827 | "name": { 2828 | "first": "Greta", 2829 | "last": "Lucas" 2830 | }, 2831 | "company": "MEDICROIX", 2832 | "email": "greta.lucas@medicroix.org", 2833 | "phone": "+1 (943) 447-2590", 2834 | "address": "381 Danforth Street, Gibbsville, Iowa, 1569", 2835 | "registered": "Tuesday, July 29, 2014 9:18 PM", 2836 | "tags": [ 2837 | "cupidatat", 2838 | "pariatur", 2839 | "dolor" 2840 | ], 2841 | "friends": [ 2842 | { 2843 | "id": 0, 2844 | "name": "Brennan Morrow" 2845 | }, 2846 | { 2847 | "id": 1, 2848 | "name": "Dolores Gamble" 2849 | }, 2850 | { 2851 | "id": 2, 2852 | "name": "Genevieve Harvey" 2853 | } 2854 | ] 2855 | }, 2856 | { 2857 | "_id": "5b420ae9e4e48d8c3cef51fe", 2858 | "index": 80, 2859 | "guid": "ac04c978-becc-4c56-892f-5f18f162416f", 2860 | "isActive": false, 2861 | "balance": "$1,469.54", 2862 | "age": 21, 2863 | "name": { 2864 | "first": "Carolyn", 2865 | "last": "Workman" 2866 | }, 2867 | "company": "EWAVES", 2868 | "email": "carolyn.workman@ewaves.io", 2869 | "phone": "+1 (802) 476-2695", 2870 | "address": "960 Fleet Walk, Mansfield, Hawaii, 832", 2871 | "registered": "Thursday, March 29, 2018 9:54 AM", 2872 | "tags": [ 2873 | "nisi", 2874 | "dolore", 2875 | "nisi" 2876 | ], 2877 | "friends": [ 2878 | { 2879 | "id": 0, 2880 | "name": "Huffman Walter" 2881 | }, 2882 | { 2883 | "id": 1, 2884 | "name": "Roberta Rodriquez" 2885 | }, 2886 | { 2887 | "id": 2, 2888 | "name": "Carly Ball" 2889 | } 2890 | ] 2891 | }, 2892 | { 2893 | "_id": "5b420ae984a73354adeab7cb", 2894 | "index": 81, 2895 | "guid": "6631c95d-62c7-453b-af18-833b1c9e927f", 2896 | "isActive": true, 2897 | "balance": "$2,595.93", 2898 | "age": 51, 2899 | "name": { 2900 | "first": "Alexis", 2901 | "last": "Whitfield" 2902 | }, 2903 | "company": "EQUICOM", 2904 | "email": "alexis.whitfield@equicom.us", 2905 | "phone": "+1 (839) 556-2836", 2906 | "address": "165 Beadel Street, Maybell, Mississippi, 857", 2907 | "registered": "Friday, November 18, 2016 5:39 PM", 2908 | "tags": [ 2909 | "deserunt", 2910 | "velit", 2911 | "Lorem" 2912 | ], 2913 | "friends": [ 2914 | { 2915 | "id": 0, 2916 | "name": "Cantu Lester" 2917 | }, 2918 | { 2919 | "id": 1, 2920 | "name": "Amber Ortiz" 2921 | }, 2922 | { 2923 | "id": 2, 2924 | "name": "Mabel Leonard" 2925 | } 2926 | ] 2927 | }, 2928 | { 2929 | "_id": "5b420ae9b2ddc162cbbe28ba", 2930 | "index": 82, 2931 | "guid": "7aa50476-9f5a-48b6-854c-943cf319f63b", 2932 | "isActive": false, 2933 | "balance": "$2,527.78", 2934 | "age": 28, 2935 | "name": { 2936 | "first": "Stein", 2937 | "last": "Madden" 2938 | }, 2939 | "company": "ZILLACTIC", 2940 | "email": "stein.madden@zillactic.ca", 2941 | "phone": "+1 (991) 598-2642", 2942 | "address": "160 Just Court, Drummond, Oregon, 3439", 2943 | "registered": "Wednesday, February 4, 2015 3:31 PM", 2944 | "tags": [ 2945 | "nostrud", 2946 | "consequat", 2947 | "irure" 2948 | ], 2949 | "friends": [ 2950 | { 2951 | "id": 0, 2952 | "name": "Bishop Conway" 2953 | }, 2954 | { 2955 | "id": 1, 2956 | "name": "Ware Downs" 2957 | }, 2958 | { 2959 | "id": 2, 2960 | "name": "Abigail Larsen" 2961 | } 2962 | ] 2963 | }, 2964 | { 2965 | "_id": "5b420ae9a142fef2ff751ea1", 2966 | "index": 83, 2967 | "guid": "61772257-8f33-435b-9644-2210015439de", 2968 | "isActive": true, 2969 | "balance": "$2,306.19", 2970 | "age": 48, 2971 | "name": { 2972 | "first": "Minnie", 2973 | "last": "Lara" 2974 | }, 2975 | "company": "PROSELY", 2976 | "email": "minnie.lara@prosely.info", 2977 | "phone": "+1 (995) 482-3279", 2978 | "address": "887 Bayview Place, Starks, Florida, 7456", 2979 | "registered": "Thursday, October 12, 2017 2:47 PM", 2980 | "tags": [ 2981 | "eiusmod", 2982 | "elit", 2983 | "dolor" 2984 | ], 2985 | "friends": [ 2986 | { 2987 | "id": 0, 2988 | "name": "Melanie Farley" 2989 | }, 2990 | { 2991 | "id": 1, 2992 | "name": "Rosario Johns" 2993 | }, 2994 | { 2995 | "id": 2, 2996 | "name": "Bridgett Russell" 2997 | } 2998 | ] 2999 | }, 3000 | { 3001 | "_id": "5b420ae9162579d4dcdf0630", 3002 | "index": 84, 3003 | "guid": "f9f58ae1-9a08-4502-ab8e-03033156525f", 3004 | "isActive": true, 3005 | "balance": "$2,587.26", 3006 | "age": 27, 3007 | "name": { 3008 | "first": "Bette", 3009 | "last": "Mckay" 3010 | }, 3011 | "company": "ZOLAVO", 3012 | "email": "bette.mckay@zolavo.net", 3013 | "phone": "+1 (966) 599-3336", 3014 | "address": "670 Kosciusko Street, Jacksonburg, New Hampshire, 3618", 3015 | "registered": "Friday, January 2, 2015 6:28 AM", 3016 | "tags": [ 3017 | "veniam", 3018 | "officia", 3019 | "laborum" 3020 | ], 3021 | "friends": [ 3022 | { 3023 | "id": 0, 3024 | "name": "Wooten Ratliff" 3025 | }, 3026 | { 3027 | "id": 1, 3028 | "name": "Daniels Holland" 3029 | }, 3030 | { 3031 | "id": 2, 3032 | "name": "Valerie Wells" 3033 | } 3034 | ] 3035 | }, 3036 | { 3037 | "_id": "5b420ae90cf0ab79dd7ebf36", 3038 | "index": 85, 3039 | "guid": "c5ed9a0a-ced0-44ea-b67a-a7cd831b3c28", 3040 | "isActive": false, 3041 | "balance": "$2,297.55", 3042 | "age": 37, 3043 | "name": { 3044 | "first": "Craft", 3045 | "last": "Barrett" 3046 | }, 3047 | "company": "EXODOC", 3048 | "email": "craft.barrett@exodoc.com", 3049 | "phone": "+1 (831) 525-3555", 3050 | "address": "741 Brigham Street, Lutsen, Vermont, 1739", 3051 | "registered": "Monday, May 2, 2016 12:53 PM", 3052 | "tags": [ 3053 | "tempor", 3054 | "ex", 3055 | "qui" 3056 | ], 3057 | "friends": [ 3058 | { 3059 | "id": 0, 3060 | "name": "Britney Collier" 3061 | }, 3062 | { 3063 | "id": 1, 3064 | "name": "April Chapman" 3065 | }, 3066 | { 3067 | "id": 2, 3068 | "name": "Frankie Clarke" 3069 | } 3070 | ] 3071 | }, 3072 | { 3073 | "_id": "5b420ae936bee66f06adc48d", 3074 | "index": 86, 3075 | "guid": "2ce3ab1b-ba40-4217-932a-1e7b546b868a", 3076 | "isActive": false, 3077 | "balance": "$3,381.02", 3078 | "age": 34, 3079 | "name": { 3080 | "first": "Crystal", 3081 | "last": "Ferguson" 3082 | }, 3083 | "company": "CENTURIA", 3084 | "email": "crystal.ferguson@centuria.me", 3085 | "phone": "+1 (816) 447-2063", 3086 | "address": "250 Indiana Place, Murillo, Massachusetts, 193", 3087 | "registered": "Wednesday, May 13, 2015 2:09 AM", 3088 | "tags": [ 3089 | "eu", 3090 | "tempor", 3091 | "dolor" 3092 | ], 3093 | "friends": [ 3094 | { 3095 | "id": 0, 3096 | "name": "Kris Webb" 3097 | }, 3098 | { 3099 | "id": 1, 3100 | "name": "Iva Farmer" 3101 | }, 3102 | { 3103 | "id": 2, 3104 | "name": "Price Hanson" 3105 | } 3106 | ] 3107 | }, 3108 | { 3109 | "_id": "5b420ae9ea662b22144b3b2e", 3110 | "index": 87, 3111 | "guid": "1f5bd9ce-3914-4e39-bace-4c1df8427fbc", 3112 | "isActive": true, 3113 | "balance": "$1,873.77", 3114 | "age": 62, 3115 | "name": { 3116 | "first": "Brittney", 3117 | "last": "Oneil" 3118 | }, 3119 | "company": "RAMEON", 3120 | "email": "brittney.oneil@rameon.tv", 3121 | "phone": "+1 (996) 400-2273", 3122 | "address": "752 Sedgwick Street, Klagetoh, Indiana, 7447", 3123 | "registered": "Wednesday, May 11, 2016 9:59 PM", 3124 | "tags": [ 3125 | "officia", 3126 | "enim", 3127 | "proident" 3128 | ], 3129 | "friends": [ 3130 | { 3131 | "id": 0, 3132 | "name": "Bauer Wilkins" 3133 | }, 3134 | { 3135 | "id": 1, 3136 | "name": "Joyce Phelps" 3137 | }, 3138 | { 3139 | "id": 2, 3140 | "name": "Bobbie Stout" 3141 | } 3142 | ] 3143 | }, 3144 | { 3145 | "_id": "5b420ae99cc137ee51063355", 3146 | "index": 88, 3147 | "guid": "56cc8d15-d5d2-49c1-8957-cada88306b3a", 3148 | "isActive": true, 3149 | "balance": "$2,297.88", 3150 | "age": 65, 3151 | "name": { 3152 | "first": "Cook", 3153 | "last": "Ashley" 3154 | }, 3155 | "company": "IMAGINART", 3156 | "email": "cook.ashley@imaginart.name", 3157 | "phone": "+1 (959) 415-3512", 3158 | "address": "713 Blake Court, Albany, Wisconsin, 8496", 3159 | "registered": "Saturday, November 1, 2014 4:14 PM", 3160 | "tags": [ 3161 | "duis", 3162 | "do", 3163 | "id" 3164 | ], 3165 | "friends": [ 3166 | { 3167 | "id": 0, 3168 | "name": "Casey Suarez" 3169 | }, 3170 | { 3171 | "id": 1, 3172 | "name": "Cathryn Griffith" 3173 | }, 3174 | { 3175 | "id": 2, 3176 | "name": "Diana Greene" 3177 | } 3178 | ] 3179 | }, 3180 | { 3181 | "_id": "5b420ae9d978835bc539f897", 3182 | "index": 89, 3183 | "guid": "83cc021c-48c8-48d7-943c-7419aed01457", 3184 | "isActive": false, 3185 | "balance": "$1,419.40", 3186 | "age": 68, 3187 | "name": { 3188 | "first": "Ashley", 3189 | "last": "Meadows" 3190 | }, 3191 | "company": "FISHLAND", 3192 | "email": "ashley.meadows@fishland.co.uk", 3193 | "phone": "+1 (971) 463-2020", 3194 | "address": "663 Glenwood Road, Wattsville, Idaho, 9832", 3195 | "registered": "Tuesday, October 28, 2014 12:04 PM", 3196 | "tags": [ 3197 | "incididunt", 3198 | "quis", 3199 | "aute" 3200 | ], 3201 | "friends": [ 3202 | { 3203 | "id": 0, 3204 | "name": "Maxwell Francis" 3205 | }, 3206 | { 3207 | "id": 1, 3208 | "name": "Annette Stafford" 3209 | }, 3210 | { 3211 | "id": 2, 3212 | "name": "Kathie Kaufman" 3213 | } 3214 | ] 3215 | }, 3216 | { 3217 | "_id": "5b420ae95d9459e3b76772ba", 3218 | "index": 90, 3219 | "guid": "3f1c52ca-9661-4966-b793-24a16d9b305b", 3220 | "isActive": true, 3221 | "balance": "$3,003.31", 3222 | "age": 20, 3223 | "name": { 3224 | "first": "Cristina", 3225 | "last": "Tran" 3226 | }, 3227 | "company": "FUELWORKS", 3228 | "email": "cristina.tran@fuelworks.biz", 3229 | "phone": "+1 (919) 493-3989", 3230 | "address": "570 Lewis Place, Sanford, Arkansas, 8398", 3231 | "registered": "Saturday, September 26, 2015 11:03 AM", 3232 | "tags": [ 3233 | "nulla", 3234 | "ullamco", 3235 | "ad" 3236 | ], 3237 | "friends": [ 3238 | { 3239 | "id": 0, 3240 | "name": "Justice Black" 3241 | }, 3242 | { 3243 | "id": 1, 3244 | "name": "Esmeralda Evans" 3245 | }, 3246 | { 3247 | "id": 2, 3248 | "name": "Dawn Grimes" 3249 | } 3250 | ] 3251 | }, 3252 | { 3253 | "_id": "5b420ae9a73155ebae460937", 3254 | "index": 91, 3255 | "guid": "6ea6909e-4a55-43bf-8255-6f036314f986", 3256 | "isActive": false, 3257 | "balance": "$1,863.14", 3258 | "age": 68, 3259 | "name": { 3260 | "first": "Tammy", 3261 | "last": "Wynn" 3262 | }, 3263 | "company": "QUORDATE", 3264 | "email": "tammy.wynn@quordate.org", 3265 | "phone": "+1 (903) 600-2793", 3266 | "address": "311 Vandam Street, Derwood, South Carolina, 530", 3267 | "registered": "Monday, December 22, 2014 4:15 PM", 3268 | "tags": [ 3269 | "ad", 3270 | "occaecat", 3271 | "esse" 3272 | ], 3273 | "friends": [ 3274 | { 3275 | "id": 0, 3276 | "name": "Page English" 3277 | }, 3278 | { 3279 | "id": 1, 3280 | "name": "Burton Rivas" 3281 | }, 3282 | { 3283 | "id": 2, 3284 | "name": "Shannon Hensley" 3285 | } 3286 | ] 3287 | }, 3288 | { 3289 | "_id": "5b420ae9484718b1f47909ef", 3290 | "index": 92, 3291 | "guid": "563d37f9-7460-462f-9927-0625ca6cfd6a", 3292 | "isActive": true, 3293 | "balance": "$1,987.10", 3294 | "age": 68, 3295 | "name": { 3296 | "first": "Nunez", 3297 | "last": "Cunningham" 3298 | }, 3299 | "company": "OVERPLEX", 3300 | "email": "nunez.cunningham@overplex.io", 3301 | "phone": "+1 (946) 448-2571", 3302 | "address": "430 Wyckoff Avenue, Garfield, Nevada, 9847", 3303 | "registered": "Sunday, May 25, 2014 9:12 AM", 3304 | "tags": [ 3305 | "proident", 3306 | "velit", 3307 | "ex" 3308 | ], 3309 | "friends": [ 3310 | { 3311 | "id": 0, 3312 | "name": "Morrow Ward" 3313 | }, 3314 | { 3315 | "id": 1, 3316 | "name": "Juliette Mendoza" 3317 | }, 3318 | { 3319 | "id": 2, 3320 | "name": "Tran Taylor" 3321 | } 3322 | ] 3323 | }, 3324 | { 3325 | "_id": "5b420ae9c350695b2d371106", 3326 | "index": 93, 3327 | "guid": "a6dfee36-56df-4fff-9b84-55a28528d7e2", 3328 | "isActive": true, 3329 | "balance": "$1,982.08", 3330 | "age": 39, 3331 | "name": { 3332 | "first": "Goldie", 3333 | "last": "Branch" 3334 | }, 3335 | "company": "KEEG", 3336 | "email": "goldie.branch@keeg.us", 3337 | "phone": "+1 (938) 565-3128", 3338 | "address": "341 Luquer Street, Dante, District Of Columbia, 4509", 3339 | "registered": "Saturday, January 20, 2018 8:34 PM", 3340 | "tags": [ 3341 | "quis", 3342 | "dolor", 3343 | "cupidatat" 3344 | ], 3345 | "friends": [ 3346 | { 3347 | "id": 0, 3348 | "name": "Louise York" 3349 | }, 3350 | { 3351 | "id": 1, 3352 | "name": "Anastasia Adams" 3353 | }, 3354 | { 3355 | "id": 2, 3356 | "name": "Lester Rios" 3357 | } 3358 | ] 3359 | }, 3360 | { 3361 | "_id": "5b420ae93ce2efbe0e4a40d6", 3362 | "index": 94, 3363 | "guid": "bb41320e-382b-4634-89cd-919a1be24521", 3364 | "isActive": false, 3365 | "balance": "$1,090.55", 3366 | "age": 24, 3367 | "name": { 3368 | "first": "Lora", 3369 | "last": "Eaton" 3370 | }, 3371 | "company": "MOLTONIC", 3372 | "email": "lora.eaton@moltonic.ca", 3373 | "phone": "+1 (956) 423-3063", 3374 | "address": "147 Cranberry Street, Marion, Utah, 4567", 3375 | "registered": "Tuesday, June 7, 2016 7:54 AM", 3376 | "tags": [ 3377 | "sint", 3378 | "nisi", 3379 | "id" 3380 | ], 3381 | "friends": [ 3382 | { 3383 | "id": 0, 3384 | "name": "Ramos Browning" 3385 | }, 3386 | { 3387 | "id": 1, 3388 | "name": "Neva Herman" 3389 | }, 3390 | { 3391 | "id": 2, 3392 | "name": "Cochran Pacheco" 3393 | } 3394 | ] 3395 | }, 3396 | { 3397 | "_id": "5b420ae9abec3302dee9c052", 3398 | "index": 95, 3399 | "guid": "cc04bdde-7125-4c8b-ba17-8aa64885f6f0", 3400 | "isActive": false, 3401 | "balance": "$1,854.76", 3402 | "age": 31, 3403 | "name": { 3404 | "first": "Franco", 3405 | "last": "Carrillo" 3406 | }, 3407 | "company": "ISOSWITCH", 3408 | "email": "franco.carrillo@isoswitch.info", 3409 | "phone": "+1 (805) 548-2213", 3410 | "address": "530 Forbell Street, Vienna, Louisiana, 1220", 3411 | "registered": "Sunday, October 9, 2016 9:34 PM", 3412 | "tags": [ 3413 | "ipsum", 3414 | "ullamco", 3415 | "pariatur" 3416 | ], 3417 | "friends": [ 3418 | { 3419 | "id": 0, 3420 | "name": "Peck Peterson" 3421 | }, 3422 | { 3423 | "id": 1, 3424 | "name": "Roach Pate" 3425 | }, 3426 | { 3427 | "id": 2, 3428 | "name": "Whitley Marks" 3429 | } 3430 | ] 3431 | }, 3432 | { 3433 | "_id": "5b420ae9b52fc81e21f21666", 3434 | "index": 96, 3435 | "guid": "d4430ebe-7e82-429a-9885-395fac0aeb2c", 3436 | "isActive": false, 3437 | "balance": "$1,464.95", 3438 | "age": 28, 3439 | "name": { 3440 | "first": "Nichole", 3441 | "last": "Mcdowell" 3442 | }, 3443 | "company": "ULTRIMAX", 3444 | "email": "nichole.mcdowell@ultrimax.net", 3445 | "phone": "+1 (961) 484-2166", 3446 | "address": "127 Chapel Street, Farmers, Rhode Island, 8610", 3447 | "registered": "Thursday, May 31, 2018 11:13 PM", 3448 | "tags": [ 3449 | "commodo", 3450 | "sit", 3451 | "amet" 3452 | ], 3453 | "friends": [ 3454 | { 3455 | "id": 0, 3456 | "name": "Schwartz Gonzalez" 3457 | }, 3458 | { 3459 | "id": 1, 3460 | "name": "Leola Buck" 3461 | }, 3462 | { 3463 | "id": 2, 3464 | "name": "Callahan Kidd" 3465 | } 3466 | ] 3467 | }, 3468 | { 3469 | "_id": "5b420ae9dbde96a7dc65d29d", 3470 | "index": 97, 3471 | "guid": "e03ead42-d62d-4ff7-a056-05b9289e2e38", 3472 | "isActive": false, 3473 | "balance": "$3,000.58", 3474 | "age": 27, 3475 | "name": { 3476 | "first": "Penny", 3477 | "last": "Foley" 3478 | }, 3479 | "company": "IMAGEFLOW", 3480 | "email": "penny.foley@imageflow.com", 3481 | "phone": "+1 (950) 568-2512", 3482 | "address": "122 Hoyt Street, Waumandee, Marshall Islands, 4335", 3483 | "registered": "Wednesday, June 21, 2017 1:50 PM", 3484 | "tags": [ 3485 | "cupidatat", 3486 | "cillum", 3487 | "nostrud" 3488 | ], 3489 | "friends": [ 3490 | { 3491 | "id": 0, 3492 | "name": "Kirby Mcmillan" 3493 | }, 3494 | { 3495 | "id": 1, 3496 | "name": "Jenny Mcgowan" 3497 | }, 3498 | { 3499 | "id": 2, 3500 | "name": "Cooper Salas" 3501 | } 3502 | ] 3503 | }, 3504 | { 3505 | "_id": "5b420ae96fb032e57d3d2956", 3506 | "index": 98, 3507 | "guid": "ca44f616-3dd7-4938-a95d-403fc55f53ac", 3508 | "isActive": true, 3509 | "balance": "$3,041.40", 3510 | "age": 34, 3511 | "name": { 3512 | "first": "Pauline", 3513 | "last": "Merrill" 3514 | }, 3515 | "company": "SCENTY", 3516 | "email": "pauline.merrill@scenty.me", 3517 | "phone": "+1 (989) 574-3364", 3518 | "address": "262 Lincoln Terrace, Kersey, American Samoa, 6732", 3519 | "registered": "May 1, 2015", 3520 | "tags": [ 3521 | "ullamco", 3522 | "officia", 3523 | "ea" 3524 | ], 3525 | "friends": [ 3526 | { 3527 | "id": 0, 3528 | "name": "Reynolds Woodard" 3529 | }, 3530 | { 3531 | "id": 1, 3532 | "name": "Sherman Booker" 3533 | }, 3534 | { 3535 | "id": 2, 3536 | "name": "Helene Herring" 3537 | } 3538 | ] 3539 | }, 3540 | { 3541 | "_id": "5b420ae917b66b4838053b0b", 3542 | "index": 99, 3543 | "guid": "d19110b6-a2a1-4484-923e-79faade32c78", 3544 | "isActive": true, 3545 | "balance": "$2,720.12", 3546 | "age": 19, 3547 | "name": { 3548 | "first": "Copeland", 3549 | "last": "Ingram" 3550 | }, 3551 | "company": "PHARMEX", 3552 | "email": "copeland.ingram@pharmex.tv", 3553 | "phone": "+1 (948) 401-3753", 3554 | "address": "865 Jardine Place, Fairhaven, Arizona, 2350", 3555 | "registered": "Saturday, January 14, 2017 12:07 AM", 3556 | "tags": [ 3557 | "qui", 3558 | "nostrud", 3559 | "commodo" 3560 | ], 3561 | "friends": [ 3562 | { 3563 | "id": 0, 3564 | "name": "Ferrell Strickland" 3565 | }, 3566 | { 3567 | "id": 1, 3568 | "name": "Jordan Montgomery" 3569 | }, 3570 | { 3571 | "id": 2, 3572 | "name": "Hickman Melendez" 3573 | } 3574 | ] 3575 | } 3576 | ] 3577 | } 3578 | 3579 | -------------------------------------------------------------------------------- /test/general.test.js: -------------------------------------------------------------------------------- 1 | import DataField from '../src/datafield' 2 | import * as data from './data.json' 3 | import error from '../src/errors' 4 | 5 | const content = data.data 6 | 7 | let dataField = new DataField(content) 8 | 9 | /* global describe it expect beforeEach */ 10 | 11 | describe('General', function () { 12 | beforeEach(function () { 13 | dataField = new DataField(content) 14 | }) 15 | 16 | describe('Constructor errors', function () { 17 | it('throws an error if no array is provided', function () { 18 | expect(() => new DataField()).toThrow('array should be passed into the DataField constructor') 19 | }) 20 | 21 | it('throws an error if no argument is not an array', function () { 22 | expect(() => new DataField({})).toThrow('DataField can only accept arrays') 23 | }) 24 | 25 | it('throws a general error if error type is unknown', function () { 26 | expect(() => error()).toThrow('DataField error') 27 | }) 28 | }) 29 | 30 | describe('Data array', function () { 31 | it('contains data for 100 entries', function () { 32 | expect(content.length).toEqual(100) 33 | }) 34 | }) 35 | 36 | describe('DataField general', function () { 37 | it('should return DataField', function () { 38 | expect(dataField instanceof DataField).toBe(true) 39 | }) 40 | 41 | it('should return proper length() via method call', function () { 42 | const length = dataField.take(6).length 43 | expect(length).toEqual(6) 44 | }) 45 | 46 | it('should return an array of 100 elements', function () { 47 | expect(dataField.values().length).toEqual(100) 48 | }) 49 | }) 50 | 51 | describe('Nested props', function () { 52 | it('should find values for nested prop', function () { 53 | const data = dataField.has('name.first') 54 | expect(data.length).toEqual(98) 55 | }) 56 | 57 | it('should find values for array', function () { 58 | const data = dataField.has('friends') 59 | expect(data.length).toEqual(98) 60 | }) 61 | 62 | it('should find nested prop', function () { 63 | const data = dataField.exists('name.first') 64 | expect(data.length).toEqual(99) 65 | }) 66 | 67 | it('should remove all entries', function () { 68 | const data = dataField.exists('name.first.test') 69 | expect(data.length).toEqual(0) 70 | }) 71 | }) 72 | describe('Includes', function () { 73 | it('should throw an error when used without selector', function () { 74 | expect(() => dataField.includes('ad')).toThrow('DataField selector not specified, use .where(selector)') 75 | }) 76 | 77 | it('should return this if no value is specified', function () { 78 | expect(dataField.where('tags').includes().length).toEqual(100) 79 | }) 80 | 81 | it('filters by array including value', function () { 82 | expect(dataField.where('tags').includes('ad').length).toEqual(5) 83 | }) 84 | }) 85 | 86 | describe('Pick Test', function () { 87 | it('should keep even elements', function () { 88 | expect(dataField.pick('even').length).toEqual(50) 89 | }) 90 | 91 | it('should keep even elements', function () { 92 | expect(dataField.pick('odd').length).toEqual(50) 93 | }) 94 | 95 | it('should keep every 3rd element', function () { 96 | expect(dataField.pick('3n').length).toEqual(34) 97 | }) 98 | 99 | it('should keep every 5th element', function () { 100 | expect(dataField.pick('5n').length).toEqual(20) 101 | }) 102 | 103 | it('should throw an error if argument is not a string', function () { 104 | expect(() => dataField.pick(42)).toThrow('DataField selector .pick() expects a string') 105 | }) 106 | 107 | it('should throw an error if argument is not right', function () { 108 | expect(() => dataField.pick("wrong string")).toThrow('DataField selector .pick() should have a proper argument value — "even", "odd" or "{number}n" (i.e. 3n for every third element)') 109 | }) 110 | 111 | it('should return this if no argument provided', function () { 112 | expect(dataField.pick().length).toEqual(100) 113 | }) 114 | }) 115 | 116 | }) 117 | 118 | 119 | -------------------------------------------------------------------------------- /test/math.test.js: -------------------------------------------------------------------------------- 1 | import DataField from '../src/datafield' 2 | import * as data from './data.json' 3 | 4 | const content = data.data 5 | 6 | let dataField = new DataField(content) 7 | 8 | /* global describe it expect beforeEach */ 9 | describe('Math operations', function () { 10 | beforeEach(function () { 11 | dataField = new DataField(content) 12 | }) 13 | 14 | describe('Sums', function () { 15 | it('should sum age values from 100 entries WITH type coercion', function () { 16 | expect(dataField.sum('age', false)).toEqual(4317) 17 | }) 18 | 19 | it('should sum age values from 100 entries WITHOUT type coercion', function () { 20 | expect(dataField.sum('age')).toEqual(4293) 21 | }) 22 | 23 | it('should sum age from selected sources', function () { 24 | const data = dataField.where('age').gt(45) 25 | expect(data.sum('age')).toEqual(2608) 26 | }) 27 | 28 | it('should throw an error if no arguments', function () { 29 | const data = dataField.where('age').gt(45) 30 | expect(() => data.sum()).toThrow('DataField selector should be passed as an argument when using math methods') 31 | }) 32 | 33 | it('should sum ages from 2 selections without WITH type coercion', function () { 34 | const dataHigh = dataField.where('age').gt(45) 35 | const dataLow = dataField.where('age').lte(45) 36 | const sum = dataHigh.sum('age', false) + dataLow.sum('age', false) 37 | expect(sum).toEqual(4317) 38 | }) 39 | }) 40 | 41 | describe('Average', function () { 42 | it('should get average for age WITH type coercion', function () { 43 | expect(dataField.avg('age', false)).toEqual(43.17) 44 | }) 45 | 46 | it('should get average for age WITHOUT type coercion', function () { 47 | expect(dataField.avg('age')).toEqual(43.36363636363637) 48 | }) 49 | 50 | it('should throw an error if no arguments', function () { 51 | const data = dataField.where('age').gt(45) 52 | expect(() => data.avg()).toThrow('DataField selector should be passed as an argument when using math methods') 53 | }) 54 | }) 55 | 56 | describe('Median', function () { 57 | it('should get median for age WITH type coercion', function () { 58 | expect(dataField.median('age', false)).toEqual(44) 59 | }) 60 | 61 | it('should get median for age WITHOUT type coercion', function () { 62 | expect(dataField.median('age')).toEqual(44) 63 | }) 64 | 65 | it('should return 0 if there are no entries', function () { 66 | expect(new DataField([]).median('age')).toEqual(0) 67 | }) 68 | 69 | it('should return value if there is only 1 value', function () { 70 | expect(new DataField([{value: 42}]).median('value')).toEqual(42) 71 | }) 72 | 73 | it('should throw an error if no arguments', function () { 74 | const data = dataField.where('age').gt(45) 75 | expect(() => data.median()).toThrow('DataField selector should be passed as an argument when using math methods') 76 | }) 77 | }) 78 | 79 | describe('Random', function () { 80 | it('should return a new DataField with a single element in it', function () { 81 | expect(dataField.takeRandom(1).length).toEqual(1) 82 | }) 83 | 84 | it('should return a new DataField with random number of elements (at least 1)', function () { 85 | expect(dataField.takeRandom()) 86 | }) 87 | 88 | it('should return a new DataField with 100 elements', function () { 89 | expect(dataField.takeRandom(100).length).toEqual(100) 90 | }) 91 | 92 | it('should return a new DataField with 100 elements', function () { 93 | expect(dataField.takeRandom(Math.floor(Math.random() * 200) + 100).length).toEqual(100) 94 | }) 95 | 96 | it('should try to parse string', function () { 97 | expect(dataField.takeRandom('7').length).toEqual(7) 98 | }) 99 | 100 | it('should try to parse string', function () { 101 | expect(dataField.takeRandom('not a number').length).toEqual(1) 102 | }) 103 | }) 104 | }) 105 | -------------------------------------------------------------------------------- /test/multiFilter.test.js: -------------------------------------------------------------------------------- 1 | import DataField from '../src/datafield' 2 | import * as data from './data.json' 3 | 4 | const content = data.data 5 | 6 | let dataField = new DataField(content) 7 | 8 | /* global describe it expect beforeEach */ 9 | describe('MultiFilter', function () { 10 | beforeEach(function () { 11 | dataField = new DataField(content) 12 | }) 13 | 14 | describe('test .any cases', function () { 15 | it('checks .gt', function () { 16 | expect(dataField.where('age').any({gt: 30}).length).toEqual(dataField.where('age').gt(30).length) 17 | }) 18 | 19 | it('checks two-zone filter', function () { 20 | expect(dataField.where('age') 21 | .any({eq: 34, lt: 30, gt: 50}).length).toEqual(67) 22 | 23 | expect(dataField.where('age') 24 | .any({lt: 30, gt: 50}).length).toEqual(64) 25 | }) 26 | 27 | }) 28 | 29 | describe('test .all cases', function () { 30 | it('checks 3 params', function () { 31 | const multi = dataField.where('age') 32 | .all({gt: 20, lt: 40, not: 36}) 33 | const chained = dataField.where('age') 34 | .gt(20).lt(40).not(36) 35 | expect(multi.length).toEqual(chained.length) 36 | }) 37 | 38 | it('checks truthy value', function () { 39 | expect(dataField.where('age').all({is: true}).length).toEqual(100) 40 | expect(dataField.where('friends').all({is: true}).length).toEqual(99) 41 | }) 42 | 43 | it('checks falsy value', function () { 44 | expect(dataField.where('friends').all({is: false}).length).toEqual(1) 45 | }) 46 | 47 | it('checks multi params', function () { 48 | expect(dataField.where('age').all( 49 | { 50 | is: true, 51 | range: [1, 100], 52 | gt: 3, 53 | gte: 50, 54 | lt: 60, 55 | lte: 80, 56 | not: 55 57 | } 58 | ).length).toEqual(17) 59 | 60 | expect(dataField.where('age').all( 61 | { 62 | is: true, 63 | range: [1, 100], 64 | gt: 3, 65 | lt: 60, 66 | lte: 80, 67 | not: 55, 68 | eq: 34 69 | } 70 | ).length).toEqual(3) 71 | 72 | expect(dataField.where('age') 73 | .all({range: [45, 55]}).length) 74 | .toEqual(dataField.where('age').range(45, 55).length) 75 | }) 76 | 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /test/range.test.js: -------------------------------------------------------------------------------- 1 | import DataField from '../src/datafield' 2 | import * as data from './data.json' 3 | 4 | const content = data.data 5 | 6 | let dataField = new DataField(content) 7 | 8 | /* global describe it expect beforeEach */ 9 | 10 | describe('Range', function () { 11 | beforeEach(function () { 12 | dataField = new DataField(content) 13 | }) 14 | describe('Different comparison types', function () { 15 | it('should throw an error as types are different', function () { 16 | const err = 'DataField range() method accepts 2 arguments of the same type' 17 | expect(() => dataField.where('index').range(1, 'str')).toThrow(err) 18 | expect(() => dataField.where('index').range('str')).toThrow(err) 19 | expect(() => dataField.where('index').range()).toThrow(err) 20 | }) 21 | }) 22 | 23 | describe('Successful filtering by index', function () { 24 | it('should filter 50 entries by index', function () { 25 | expect(dataField.where('index').range(0, 50).length).toEqual(50) 26 | }) 27 | }) 28 | 29 | describe('Successful filtering by date', function () { 30 | it('should filter 65 entries', function () { 31 | expect(dataField.where('registered').range(new Date('may 3, 1980'), new Date('jan 1, 2017')).length).toEqual(65) 32 | }) 33 | }) 34 | 35 | describe('Successful filtering by alphabet', function () { 36 | it('select from A to C', function () { 37 | expect(dataField.where('name.first').range('A', 'C').length).toEqual(16) 38 | }) 39 | it('select from U to Zz', function () { 40 | expect(dataField.where('name.first').range('U', 'Zz').length).toEqual(6) 41 | }) 42 | }) 43 | 44 | describe('Successful filtering by array length', function () { 45 | it('selects arrays with length >0', function () { 46 | expect(dataField.where('friends').range(1, 100).length).toEqual(98) 47 | }) 48 | }) 49 | 50 | describe('Successful filtering by array length (take only length of 2)', function () { 51 | it('selects arrays with length >0', function () { 52 | expect(dataField.where('friends').range(2, 3).length).toEqual(1) 53 | }) 54 | }) 55 | 56 | }) 57 | -------------------------------------------------------------------------------- /test/sorting.test.js: -------------------------------------------------------------------------------- 1 | import DataField from '../src/datafield' 2 | import * as data from './data.json' 3 | 4 | const content = data.data 5 | 6 | let dataField = new DataField(content) 7 | 8 | /* global describe it expect beforeEach */ 9 | 10 | describe('Sorting', function () { 11 | 12 | beforeEach(function () { 13 | dataField = new DataField(content) 14 | }) 15 | 16 | it('should throw an error', function () { 17 | expect(() => dataField.asc()).toThrow('DataField selector not specified, use .where(selector)') 18 | }) 19 | 20 | it('should throw an error on empty set', function () { 21 | expect(() => new DataField([]).asc()).toThrow('DataField selector not specified, use .where(selector)') 22 | }) 23 | 24 | it('should return unchanged dataset when sorting type is not supported', function () { 25 | expect(dataField.where('age').asc().length).toEqual(100) 26 | }) 27 | 28 | it('should throw an error', function () { 29 | expect(() => dataField.desc()).toThrow('DataField selector not specified, use .where(selector)') 30 | }) 31 | 32 | it('should sort data alphabetically', function () { 33 | const name = dataField.where('name.last').asc().toArray()[0].name.last 34 | expect(name).toEqual('Abbott') 35 | }) 36 | 37 | it('should sort data alphabetically in descending order', function () { 38 | const name = dataField.where('name.last').desc().toArray()[0].name.last 39 | expect(name).toEqual('Yates') 40 | }) 41 | 42 | it('should sort data by age in ascending order', function () { 43 | const name = dataField.where('age').asc().toArray()[0].age 44 | expect(name).toEqual(19) 45 | }) 46 | 47 | it('should sort data by age in descending order', function () { 48 | const name = dataField.where('age').desc().toArray()[0].age 49 | expect(name).toEqual(68) 50 | }) 51 | 52 | it('should return unchanged if type is not right - using asc()', function () { 53 | const name = dataField.sort({by: 'isActive'}).toArray()[0].age 54 | expect(name).toEqual(41) 55 | }) 56 | 57 | it('should return unchanged if type is not right - using desc()', function () { 58 | const name = dataField.sort({by: 'isActive', order: 'desc'}).toArray()[0].age 59 | expect(name).toEqual(41) 60 | }) 61 | 62 | it('should sort data using sort() method', function () { 63 | const company = dataField.sort({by: 'company', order: 'desc', type: 'string'}).toArray()[0].company 64 | expect(company).toEqual('ZOLAVO') 65 | }) 66 | 67 | it('should sort data using sort() method, defaulting to "asc" order and "string" type', function () { 68 | const company = dataField.sort({by: 'company'}).toArray()[0].company 69 | expect(company).toEqual('ANIVET') 70 | }) 71 | 72 | it('should sort by string type because "date" type is not passed, using desc() method', function () { 73 | const company = dataField.where('registered').desc().toArray()[0].company 74 | expect(company).toEqual('EXIAND') 75 | }) 76 | 77 | it('should sort by string type because "date" type is not passed, using asc() method', function () { 78 | const company = dataField.where('registered').asc().toArray()[0].company 79 | expect(company).toEqual('BOILCAT') 80 | }) 81 | 82 | it('should sort data by date', function () { 83 | const company = dataField.sort({by: 'registered', type: 'date'}).toArray()[0].company 84 | expect(company).toEqual('ISOTRACK') 85 | }) 86 | 87 | it('should sort data by date in descending order', function () { 88 | const company = dataField.sort({by: 'registered', order: 'desc', type: 'date'}).toArray()[0].company 89 | expect(company).toEqual('PAPRIKUT') 90 | }) 91 | 92 | it('should sort data by friends array length', function () { 93 | const company = dataField.where('friends').asc().toArray()[0].company 94 | expect(company).toEqual('SUREMAX') 95 | }) 96 | 97 | it('should sort data by friends array length in descending order', function () { 98 | const company = dataField.where('friends').desc().toArray()[0].company 99 | expect(company).toEqual('COMTENT') 100 | }) 101 | 102 | }) 103 | --------------------------------------------------------------------------------