json-aggregate
What is it?
json-aggregate is a javascript utility to perform aggregations on JSON-formatted data. It is inspired by the MongoDB Aggregation Framework, but in no way pretends to cover all its functionality.
Why?
json-aggregate allows developers to perform aggregation queries on JSON data without the need to store it. Nowadays the average app sends/receives JSON from multiple sources/apis/etc., and this utility can help developers extract some insights from the data without the need to use a database.
How to use
Install via npm / yarn:
npm install json-aggregate
Use the create method with the JSON data to generate a collection:
const jsonAggregate = require('json-aggregate')
const collection = jsonAggregate.create(myJsonData)
Methods
match (options)
options | object | function |
Filters the documents and only those that match the specified criteria are returned.
Data
[{ "author" : "dave", "score" : 80, "views" : 100 },
{ "author" : "dave", "score" : 85, "views" : 521 },
{ "author" : "ahn", "score" : 60, "views" : 1000 },
{ "author" : "li", "score" : 55, "views" : 5000 },
{ "author" : "annT", "score" : 60, "views" : 50 },
{ "author" : "li", "score" : 94, "views" : 999 },
{ "author" : "ty", "score" : 95, "views" : 1000 }]
Aggregation
collection.match({ author : "dave" }).exec()
Result
[{ "author" : "dave", "score" : 80, "views" : 100 }
{ "author" : "dave", "score" : 85, "views" : 521 }]
Alternatively, the same result can be achieved with a condition function:
collection.match(item => item.author === "dave").exec()
unwind (field)
field | string |
Deconstructs an array field and returns a single record for each of its values.
Data{ "item" : "ABC1", sizes: [ "S", "M", "L"] }
Aggregation
collection.unwind("sizes").exec()
Results
[{ "item" : "ABC1", "sizes" : "S" },
{ "item" : "ABC1", "sizes" : "M" },
{ "item" : "ABC1", "sizes" : "L" }]
group (options)
options | string | array | object |
Groups documents by the specified options and returns the aggregated data with each group having a distinct id field.
Data
[{ company: "a", employeeCount: 45, category: 1, product: "Product A", price: 120 },
{ company: "a", employeeCount: 45, category: 1, product: "Product B", price: 80 },
{ company: "a", employeeCount: 45, category: 2, product: "Product C", price: 105 },
{ company: "a", employeeCount: 45, category: 2, product: "Product D", price: 95 },
{ company: "b", employeeCount: 30, category: 1, product: "Product A", price: 40 },
{ company: "b", employeeCount: 30, category: 1, product: "Product B", price: 100 },
{ company: "b", employeeCount: 30, category: 2, product: "Product C", price: 60 },
{ company: "b", employeeCount: 30, category: 2, product: "Product D", price: 130 }]
Aggregation #1
collection.group('company').exec()
// or collection.group({ id: 'company' })
Results #1
["a", "b"]
Aggregation #2 (with operator)
collection.group({
id: 'company',
lowestPrice: { $min: 'price'}
})
.exec()
Results #2
[{ id: 'a', lowestPrice: 80 },
{ id: 'b', lowestPrice: 40 }]
Aggregation #3 (multiple keys)
collection.group({
id: ['company', 'category'],
max: { $max: 'price' }
})
.exec()
Results #3
[{ id: { company: 'a', category: 1 }, max: 120 },
{ id: { company: 'a', category: 2 }, max: 105 },
{ id: { company: 'b', category: 1 }, max: 100 },
{ id: { company: 'b', category: 2 }, max: 130 }]
sort (criteria)
criteria | object |
Sorts values according to the criteria passed.
Data
[{ company: 'a', price: 90 },
{ company: 'b', price: 120 },
{ company: 'b', price: 50 }]
Aggregation
collection.sort({ company: -1, price: 1 }).exec()
Results
[{ company: 'b', price: 50 },
{ company: 'b', price: 120 },
{ company: 'a', price: 90 }]
limit (n)
n | number |
Shrinks the array of results to the desired length. An Array.slice proxy for convenience (in chaining).
Data
[{ company: "a", employeeCount: 45, category: 1, product: "Product A", price: 120 },
{ company: "a", employeeCount: 45, category: 1, product: "Product B", price: 80 },
{ company: "a", employeeCount: 45, category: 2, product: "Product C", price: 105 },
{ company: "a", employeeCount: 45, category: 2, product: "Product D", price: 95 },
{ company: "b", employeeCount: 30, category: 1, product: "Product A", price: 40 },
{ company: "b", employeeCount: 30, category: 1, product: "Product B", price: 100 },
{ company: "b", employeeCount: 30, category: 2, product: "Product C", price: 60 },
{ company: "b", employeeCount: 30, category: 2, product: "Product D", price: 130 }]
Aggregation
collection.sort({ price: -1 }).limit(2).exec()
Results
[{ company: "b", employeeCount: 30, category: 2, product: "Product D", price: 130 },
{ company: "a", employeeCount: 45, category: 1, product: "Product A", price: 120 }]
Operators
Data
[{ company: "a", employeeCount: 45, category: 1, product: "Product A", price: 120 },
{ company: "a", employeeCount: 45, category: 1, product: "Product B", price: 80 },
{ company: "a", employeeCount: 45, category: 2, product: "Product C", price: 105 },
{ company: "a", employeeCount: 45, category: 2, product: "Product D", price: 95 },
{ company: "b", employeeCount: 30, category: 1, product: "Product A", price: 40 },
{ company: "b", employeeCount: 30, category: 1, product: "Product B", price: 100 },
{ company: "b", employeeCount: 30, category: 2, product: "Product C", price: 60 },
{ company: "b", employeeCount: 30, category: 2, product: "Product D", price: 130 }]
$avg
Returns the average of the selected field for the group of records.
Aggregation
collection.group({ id: 'product', count: { $avg: 'price' } }).exec()
Result
[{ id: 'Product A', count: 80 },
{ id: 'Product B', count: 90 },
{ id: 'Product C', count: 82.5 },
{ id: 'Product D', count: 112.5 }]
$first
Returns the first record found for each group.
Aggregation
collection.group({ id: 'company', product: { $first: 'product' } }).exec()
Result
[{ id: 'a', product: 'Product A'},
{ id: 'b', product: 'Product A'}]
$last
Returns the last record found for each group.
Aggregation
collection.group({ id: 'company', product: { $last: 'product' } }).exec()
Result
[{ id: 'a', product: 'Product D'},
{ id: 'b', product: 'Product D'}]
$min
Returns the minimum value found for the chosen field of each group.
Aggregation
collection.group({ id: 'company', lowestPrice: { $min: 'price' } }).exec()
Result
[{ id: 'a', lowestPrice: 80 },
{ id: 'b', lowestPrice: 40 }]
$max
Returns the maximum value found for the chosen field of each group.
Aggregation
collection.group({ id: 'company', highestPrice: { $max: 'price' } }).exec()
Result
[{ id: 'a', highestPrice: 120 },
{ id: 'b', highestPrice: 130 }]
$sum
Returns the sum of all the values from the chosen field of each group. Admits the value 1 to perform a count of the records within each group.
Aggregation
collection.group({ id: 'company', count: { $sum: 1 } }).exec()
Result
[{ id: 'a', count: 4 },
{ id: 'b', count: 4 }]
$push
Appends the values of specific fields into each group. This operator expects an array.
Aggregation
collection.group({ id: 'company', products: { $push: ['product', 'price'] }).exec()
Result
[{ id: 'a',
products: [
{ product: 'Product A', price: 120 },
{ product: 'Product B', price: 80 },
{ product: 'Product C', price: 105 },
{ product: 'Product D', price: 95 }
]
},
{ id: 'b',
products: [
{ product: 'Product A', price: 40 },
{ product: 'Product B', price: 100 },
{ product: 'Product C', price: 60 },
{ product: 'Product D', price: 130 }
]
}]
$addToSet
Adds unique values present in the chosen field for each group.
Aggregation
collection.group({ id: 'company', categories: { $addToSet: 'category' } }).exec()
Result
[{ id: 'a', categories: [1, 2] },
{ id: 'b', categories: [1, 2] }]
Full example
Data
[{ shop: "XYZ", "item" : "A", sizes: [ "S", "M", "L"], price: '99' },
{ shop: "XYZ", "item" : "B", sizes: [ "M", "L"], price: '69' },
{ shop: "XYZ", "item" : "C", sizes: [ "S", "L", "XL"], price: '120' },
{ shop: "MNO", "item" : "A", sizes: [ "S" ], price: '110' },
{ shop: "MNO", "item" : "B", sizes: [ "S", "M", "L"], price: '80' },
{ shop: "MNO", "item" : "C", sizes: [ "S", "M", "XL"], price: '100' },
{ shop: "JKL", "item" : "A", sizes: [ "S", "M", "XL" ], price: '105' },
{ shop: "JKL", "item" : "B", sizes: [ "M", "L"], price: '50' },
{ shop: "JKL", "item" : "C", sizes: [ "M", "XL"], price: '110' }]
Aggregation
collection
.match(item => item.price > 60)
.unwind('sizes')
.group({
id: ['item', 'sizes'],
whereToBuy: { $push: ['shop', 'price'] }
})
.exec()
Result
[{
"id": {"item": "A", "sizes": "L"},
"whereToBuy": [{"price": "99", "shop": "XYZ"}]
},{
"id": {"item": "C", "sizes": "L"},
"whereToBuy": [{"price": "120", "shop": "XYZ"}]
},{
"id": {"item": "B", "sizes": "S"},
"whereToBuy": [{"price": "80", "shop": "MNO"}]
},{
"id": {"item": "B", "sizes": "M"},
"whereToBuy": [{"price": "69", "shop": "XYZ"},{"price": "80", "shop": "MNO"}]
},{
"id": {"item": "B", "sizes": "L"},
"whereToBuy": [{"price": "69", "shop": "XYZ"}, {"price": "80", "shop": "MNO"}]
},{
"id": {"item": "C", "sizes": "S"},
"whereToBuy": [{"price": "120", "shop": "XYZ"},{"price": "100", "shop": "MNO"}]
},{
"id": {"item": "A", "sizes": "S"},
"whereToBuy": [{"price": "99", "shop": "XYZ"}, {"price": "110", "shop": "MNO"}, {"price": "105", "shop": "JKL"}]
},{
"id": {"item": "A", "sizes": "M"},
"whereToBuy": [{"price": "99", "shop": "XYZ"},{"price": "105", "shop": "JKL"}]
},{
"id": {"item": "A", "sizes": "XL"},
"whereToBuy": [{"price": "105", "shop": "JKL"}]
},{
"id": {"item": "C", "sizes": "M"},
"whereToBuy": [{"price": "100", "shop": "MNO"},{"price": "110", "shop": "JKL"}]
},{
"id": {"item": "C", "sizes": "XL"},
"whereToBuy": [{"price": "120", "shop": "XYZ"}, {"price": "100", "shop": "MNO"}, {"price": "110", "shop": "JKL"}]
}]