Related
I am creating a query in MongoDB which works correctly for me but in the end I have to do an extra grouping to get the response grouped by year. This is the query:
db.sales.aggregate([
{
$group: {
_id: {
month: {
$month: "$createdAt"
},
year: {
$year: "$createdAt"
},
dayOfWeek: {
$dayOfWeek: "$createdAt"
},
stringDay: {
$dateToString:
{ format: "%Y-%m-%d", date: "$createdAt"}
},
week: {
$isoWeek: "$createdAt"
}
},
total: { $sum: '$total'},
count: { $sum: 1 },
totalAverage: { $avg: '$total'}
}
},
{
$sort : {
"_id.month" : 1
}
},
{
$project: {
total: { $round: [ "$total", 2 ] },
year: "$_id.year",
date: "$_id.date",
week: "$_id.week",
numVentas: "$count",
month: "$_id.month",
dayOfWeek: "$_id.dayOfWeek",
stringDay:"$_id.stringDay",
count: "$count",
totalAverage: { $round: [ "$totalAverage", 2 ] },
stringMonth: {
$arrayElemAt: [
[
"",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"$_id.month"
]
},
stringWeek: {
$switch: {
branches:[
{ case: { $eq: ["$_id.dayOfWeek", 1] }, then: "Lunes" },
{ case: { $eq: ["$_id.dayOfWeek", 2] }, then: "Martes" },
{ case: { $eq: ["$_id.dayOfWeek", 3] }, then: "Miércoles" },
{ case: { $eq: ["$_id.dayOfWeek", 4] }, then: "Jueves" },
{ case: { $eq: ["$_id.dayOfWeek", 5] }, then: "Viernes" },
{ case: { $eq: ["$_id.dayOfWeek", 6] }, then: "Sábado" },
{ case: { $eq: ["$_id.dayOfWeek", 7] }, then: "Domingo" }
],
default: "Día desconocido"
}
}
}
},
{
$group: {
_id: { month: "$stringMonth", year: "$year"},
count: { $sum: "$count" },
total: { $sum: "$total" },
totalAverage: { $sum: "$totalAverage" },
sales: {
$push: {
numberDay: "$dayOfWeek",
stringWeek: "$stringWeek",
date: "$stringDay",
total: "$total",
count: "$count",
totalAverage: { $round: [ "$totalAverage", 2 ] }
}
}
}
},
{
$group: {
_id: "$_id.year",
monthsWithSales: { $sum: 1 },
count: { $sum: "$count" },
total: { $sum: "$total" },
totalAverage: { $sum: "$totalAverage" },
sales: {
$push: {
mes: "$_id.month",
count: "$count",
total: "$total",
totalAverage: "$totalAverage",
sales:"$sales"
}
}
}
}
])
And I get this response:
[
{
"_id": 2022,
"monthsWithSales": 4,
"count": 57,
"total": 22324.8,
"totalAverage": 7765.799999999999,
"sales": [
{
"mes": "Oct",
"count": 10,
"total": 1936,
"totalAverage": 1233.6,
"sales": [
{
"numberDay": 6,
"stringWeek": "Sábado",
"date": "2022-10-21",
"total": 526.8,
"count": 3,
"totalAverage": 175.6
},
{
"numberDay": 1,
"stringWeek": "Lunes",
"date": "2022-10-02",
"total": 85.6,
"count": 1,
"totalAverage": 85.6
},
{
"numberDay": 7,
"stringWeek": "Domingo",
"date": "2022-10-22",
"total": 526.8,
"count": 3,
"totalAverage": 175.6
},
{
"numberDay": 3,
"stringWeek": "Miércoles",
"date": "2022-10-04",
"total": 180,
"count": 1,
"totalAverage": 180
},
{
"numberDay": 4,
"stringWeek": "Jueves",
"date": "2022-10-12",
"total": 531.2,
"count": 1,
"totalAverage": 531.2
},
{
"numberDay": 3,
"stringWeek": "Miércoles",
"date": "2022-10-25",
"total": 85.6,
"count": 1,
"totalAverage": 85.6
}
]
},
{
"mes": "Nov",
"count": 7,
"total": 2205.2,
"totalAverage": 1014.8,
"sales": [
{
"numberDay": 4,
"stringWeek": "Jueves",
"date": "2022-11-02",
"total": 526.8,
"count": 3,
"totalAverage": 175.6
},
{
"numberDay": 6,
"stringWeek": "Sábado",
"date": "2022-11-25",
"total": 171.2,
"count": 2,
"totalAverage": 85.6
},
{
"numberDay": 7,
"stringWeek": "Domingo",
"date": "2022-11-12",
"total": 1507.2,
"count": 2,
"totalAverage": 753.6
}
]
},
{
"mes": "Dec",
"count": 33,
"total": 12587.6,
"totalAverage": 4074.5,
"sales": [
{
"numberDay": 3,
"stringWeek": "Miércoles",
"date": "2022-12-06",
"total": 850,
"count": 1,
"totalAverage": 850
},
{
"numberDay": 6,
"stringWeek": "Sábado",
"date": "2022-12-02",
"total": 8737.6,
"count": 25,
"totalAverage": 349.5
},
{
"numberDay": 7,
"stringWeek": "Domingo",
"date": "2022-12-10",
"total": 900,
"count": 1,
"totalAverage": 900
},
{
"numberDay": 1,
"stringWeek": "Lunes",
"date": "2022-12-04",
"total": 200,
"count": 1,
"totalAverage": 200
},
{
"numberDay": 2,
"stringWeek": "Martes",
"date": "2022-12-05",
"total": 500,
"count": 1,
"totalAverage": 500
},
{
"numberDay": 5,
"stringWeek": "Viernes",
"date": "2022-12-08",
"total": 250,
"count": 2,
"totalAverage": 125
},
{
"numberDay": 4,
"stringWeek": "Jueves",
"date": "2022-12-07",
"total": 250,
"count": 1,
"totalAverage": 250
},
{
"numberDay": 6,
"stringWeek": "Sábado",
"date": "2022-12-09",
"total": 900,
"count": 1,
"totalAverage": 900
}
]
},
{
"mes": "Sep",
"count": 7,
"total": 5596,
"totalAverage": 1442.8999999999999,
"sales": [
{
"numberDay": 2,
"stringWeek": "Martes",
"date": "2022-09-12",
"total": 5069.2,
"count": 4,
"totalAverage": 1267.3
},
{
"numberDay": 6,
"stringWeek": "Sábado",
"date": "2022-09-02",
"total": 526.8,
"count": 3,
"totalAverage": 175.6
}
]
}
]
},
{
"_id": 2021,
"monthsWithSales": 1,
"count": 2,
"total": 608,
"totalAverage": 608,
"sales": [
{
"mes": "Dec",
"count": 2,
"total": 608,
"totalAverage": 608,
"sales": [
{
"numberDay": 1,
"stringWeek": "Lunes",
"date": "2021-12-12",
"total": 171.2,
"count": 1,
"totalAverage": 171.2
},
{
"numberDay": 4,
"stringWeek": "Jueves",
"date": "2021-12-22",
"total": 436.8,
"count": 1,
"totalAverage": 436.8
}
]
}
]
}
]
It is correct, but as you can see at the end I make two groups to obtain the data grouped by year and then the sales array grouped by month.
Is there any way to improve this query without so much grouping?
I made a line change via axios.path, but after changes in db.json I constantly need to reload the page. How can I avoid this and make the data update automatically?
const submitEdits = (item) => {
axios.patch(`http://localhost:3004/item/${item.id}`, { text: editingText })
setIdItem(null);
setEditingText('')
}
My db.json
{
"item": [
{
"text": "123123123",
"id": 0,
"data": {
"year": 2012,
"day": 25,
"month": 1
}
},
{
"text": "Поступил в институт",
"id": 1,
"data": {
"year": 2007,
"day": 12,
"month": 4
}
},
{
"id": 2,
"text": "123",
"data": {
"year": 2022,
"day": 16,
"month": 5
}
}
]
}
I have array of objects
{
"agent_name": "AgentName",
"analytics": [
{
"date": "Tue, 1 Aug 2021 00:00:00 GMT",
"intents_count":[
{
"count": 5,
"intent": "intent1"
},
{
"count": 1,
"intent": "intent2"
},
{
"count": 0,
"intent": "intent3"
},
]
},
{
"date": "Tue, 2 Aug 2021 00:00:00 GMT",
"intents_count":[
{
"count": 5,
"intent": "intent1"
},
{
"count": 1,
"intent": "intent2"
},
{
"count": 0,
"intent": "intent3"
},
]
},
... the same for the next days of month
]
}
I need to get the sum of count for each intent grouped by date.
The result should be something like this:
[10, 2, 0]
where 10 correspond to sum of count field of the intent 'intent1' during all days.
You need to first flat and select the required array "analytics". Then use groupBy and sum to get the final result.
let data = {
"agent_name": "AgentName",
"analytics": [
{
"date": "Tue, 1 Aug 2021 00:00:00 GMT",
"intents_count":[
{
"count": 5,
"intent": "intent1"
},
{
"count": 1,
"intent": "intent2"
},
{
"count": 0,
"intent": "intent3"
},
]
},
{
"date": "Tue, 2 Aug 2021 00:00:00 GMT",
"intents_count":[
{
"count": 5,
"intent": "intent1"
},
{
"count": 1,
"intent": "intent2"
},
{
"count": 0,
"intent": "intent3"
},
]
},
]
}
let flatResult = _.flatMap(data.analytics, 'intents_count');
let result = _(flatResult).groupBy('intent').map(x => _.sumBy(x, 'count'));
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
I have a high level solution to what can be done. This is not using lodash operators, but can be a good starting point.
const data = {
"agent_name": "AgentName",
"analytics": [{
"date": "Tue, 1 Aug 2021 00:00:00 GMT",
"intents_count": [{
"count": 5,
"intent": "intent1"
},
{
"count": 1,
"intent": "intent2"
},
{
"count": 0,
"intent": "intent3"
},
]
},
{
"date": "Tue, 2 Aug 2021 00:00:00 GMT",
"intents_count": [{
"count": 5,
"intent": "intent1"
},
{
"count": 1,
"intent": "intent2"
},
{
"count": 0,
"intent": "intent3"
},
]
}
]
}
const arr = [];
data.analytics.forEach(intentObj => {
intentObj.intents_count.forEach(obj => {
//calculating the index to store the value in array.
const index = obj.intent[6] - 1;
if (arr[index] !== undefined) {
arr[index] = arr[index] + obj.count;
} else {
arr[index] = obj.count;
}
});
});
console.log(arr);
I don't have much experience with mongodb, so the following query is making it difficult for me.
This is the document
[
{
"_id": "31-07-2019",
"date": "31-07-2019",
"grocerie1": [
{
"name": "Flour",
"price": 3.68,
"count": 1
},
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Flour",
"price": 3.68,
"count": 1
}
],
"grocerie2": [
{
"name": "Flour",
"price": 3.68,
"count": 1
}
],
"grocerie1Total": 13.36,
"grocerie2Total": 3.68,
"total": 17.04
},
{
"_id": "09-08-2019",
"date": "09-08-2019",
"grocerie1": [
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Milk",
"price": 5,
"count": 1
}
],
"grocerie2": [
{
"name": "Milk",
"price": 5,
"count": 1
},
{
"name": "Cheese",
"price": 2,
"count": 1
}
],
"grocerie1Total": 11,
"grocerie2Total": 7,
"total": 18
},
{
"_id": "22-08-2019",
"date": "22-08-2019",
"grocerie1": [
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Cheese",
"price": 2,
"count": 1
},
{
"name": "Cheese",
"price": 2,
"count": 1
},
{
"name": "Rice",
"price": 3,
"count": 1
}
],
"grocerie2": [
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Rice",
"price": 3,
"count": 1
},
{
"name": "Rice",
"price": 3,
"count": 1
}
],
"grocerie1Total": 10,
"grocerie2Total": 9,
"total": 19
}
]
The document is sorted by date, and contains two grocery stores, each with different products sold. Each product has a name, price and a "count" that I placed to, in the future, obtain the number of times the product was sold through the sum of this field.
Now I want to achieve something like this:
[
{
"_id": "31-07-2019",
"date": "31-07-2019",
"grocerie1": [
{
"name": "Flour",
"total": 7.56,
"count": 2
},
{
"name": "Rice",
"total": 6,
"count": 2
}
],
"grocerie2": [
{
"name": "Flour",
"total": 3.68,
"count": 1
}
],
"grocerie1Total": 13.36,
"grocerie2Total": 3.68,
"total": 17.04
},
{
"_id": "09-08-2019",
"date": "09-08-2019",
"grocerie1": [
{
"name": "Rice",
"total": 6,
"count": 2
},
{
"name": "Milk",
"total": 5,
"count": 1
}
],
"grocerie2": [
{
"name": "Milk",
"total": 5,
"count": 1
},
{
"name": "Cheese",
"total": 2,
"count": 1
}
],
"grocerie1Total": 11,
"grocerie2Total": 7,
"total": 18
},
{
"_id": "22-08-2019",
"date": "22-08-2019",
"grocerie1": [
{
"name": "Rice",
"total": 6,
"count": 2
},
{
"name": "Cheese",
"total": 4,
"count": 2
}
],
"grocerie2": [
{
"name": "Rice",
"total": 9,
"count": 3
}
],
"grocerie1Total": 10,
"grocerie2Total": 9,
"total": 19
}
]
I tried something like this, for example, for "grocerie1",
however, I got disastrous results:
{
$unwind:
{
path: "$grocerie1",
preserveNullAndEmptyArrays: true
}
},
{
"$group": {
"_id": "$grocerie1.name",
"eatHereInfo": {
"$push": {
"name": "$grocerie1.name",
"total": { "$sum": "$grocerie1.price" },
"count": { "$sum": "$grocerie1.count" } }
},
"grocerie2": { "$first": "$grocerie2" },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" },
}
},
Is there any way to achieve it with the aggregation framework? or with javascript? Any help and suggestion are appreciated :)
Note: I assume your objects stored in grocerie collection.
Mongo way (Difficult and rigid)
db.getCollection('grocerie').aggregate([
// ---------------- We start with grocerie1 ------------------
//1. Split grocerie1 array into atomic object
{"$unwind":{ "path": "$grocerie1", "preserveNullAndEmptyArrays": true }},
//2. Group by date + grocerie1 name. If group only by grocerie1.name we may group from other days
// For same grocerie names, we accumulate their name, price, total "grocerie1": { "$push": "$grocerie1" },
{"$group": {
"_id": { "_id": "$_id", "name": "$grocerie1.name" },
"grocerie1": { "$push": "$grocerie1" },
"grocerie2": { "$first": "$grocerie2" },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" }
}
},
//3. Now we have unique date + grocerie1 names + all same items inside grocerie1 array. Split again into atomic value
{"$unwind":{ "path": "$grocerie1", "preserveNullAndEmptyArrays": true }},
//4. We group again date + grocerie1 names, but now we sum price and count
{"$group": {
"_id": { "_id": "$date", "name": "$_id.name" },
"total": { "$sum": "$grocerie1.price" },
"count": { "$sum": "$grocerie1.count" },
"grocerie2": { "$first": "$grocerie2" },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" }
}
},
//5. We group for date and push inside grocerie1 calculated price, total
{"$group":{
"_id": "$_id._id",
"grocerie1": { "$push": {
"name" : "$_id.name",
"total" : "$total",
"count" : "$count"
} },
"grocerie2": { "$first": "$grocerie2" },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" }
}
},
// ---------------- We finished with grocerie1 ---------------
// ---------------- We start with grocerie2 ------------------
//1. Split grocerie2 array into atomic object
{"$unwind":{ "path": "$grocerie2", "preserveNullAndEmptyArrays": true }},
//2. Group by date + grocerie2 name. If group only by grocerie2.name we may group from other days
// For same grocerie names, we accumulate their name, price, total "grocerie2": { "$push": "$grocerie2" },
{"$group": {
"_id": { "_id": "$_id", "name": "$grocerie2.name" },
"grocerie1": { "$first": "$grocerie1" },
"grocerie2": { "$push": "$grocerie2" },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" }
}
},
//3. Now we have unique date + grocerie2 names + all same items inside grocerie2 array. Split again into atomic value
{"$unwind":{ "path": "$grocerie2", "preserveNullAndEmptyArrays": true }},
//4. We group again date + grocerie2 names, but now we sum price and count
{"$group": {
"_id": { "_id": "$date", "name": "$_id.name" },
"total": { "$sum": "$grocerie2.price" },
"count": { "$sum": "$grocerie2.count" },
"grocerie1": { "$first": "$grocerie1" },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" }
}
},
//5. We group for date and push inside grocerie2 calculated price, total
{"$group":{
"_id": "$_id._id",
"grocerie1": { "$first": "$grocerie1" },
"grocerie2": { "$push": {
"name" : "$_id.name",
"total" : "$total",
"count" : "$count"
} },
"date": { "$first": "$date" },
"grocerie1Total": { "$first": "$grocerie1Total" },
"grocerie2Total": { "$first": "$grocerie2Total" },
// Sum total values
"total" : {"$sum":{"$add":["$grocerie1Total", "$grocerie2Total"]}}
}
}
// ---------------- We finished with grocerie2 ---------------
])
Javascript way (Easy and flexible)
/**
* Group groceries with same name and sum fields
*/
function groupGroceries(){
//aux function to group groceries with same name
function _(grocerie){
for(var i=grocerie.length-1; i > -1; i--){
for(var j=0; j<i; j++){
// If grocerie.name already exists, we sum values and remove from array
if(grocerie[j].name == grocerie[i].name){
grocerie[j].price += grocerie[i].price;
grocerie[j].count += grocerie[i].count;
grocerie.splice(i, 1);
break;
}
}
}
//Change price into total
for(var i=0; i<grocerie.length; i++){
//Robo 3T bug: (""+grocerie[i].price).indexOf(".") > -1 ? grocerie[i].price : NumberInt(grocerie[i].price);
grocerie[i].total = grocerie[i].price;
delete grocerie[i].price;
}
}
var result = [];
//Iterate over grocerie collection
db.getCollection('grocerie').find({}).forEach(function(doc){
//Uncomment line below if _id disappears
//doc["_id"];
_(doc.grocerie1);
_(doc.grocerie2);
doc.total = doc.grocerie1Total + doc.grocerie2Total;
result.push(doc);
})
for(var i=0; i<result.length; i++){
print("/* " + (i+1) + " */")
print(result[i])
print("")
}
}
groupGroceries();
==Result==
/* 1 */
{
"_id" : "31-07-2019",
"grocerie1" : [
{
"name" : "Flour",
"total" : 7.36,
"count" : 2
},
{
"name" : "Rice",
"total" : 6,
"count" : 2
}
],
"grocerie2" : [
{
"name" : "Flour",
"total" : 3.68,
"count" : 1
}
],
"date" : "31-07-2019",
"grocerie1Total" : 13.36,
"grocerie2Total" : 3.68,
"total" : 17.04
}
/* 2 */
{
"_id" : "09-08-2019",
"grocerie1" : [
{
"name" : "Rice",
"total" : 6,
"count" : 2
},
{
"name" : "Milk",
"total" : 5,
"count" : 1
}
],
"grocerie2" : [
{
"name" : "Milk",
"total" : 5,
"count" : 1
},
{
"name" : "Cheese",
"total" : 2,
"count" : 1
}
],
"date" : "09-08-2019",
"grocerie1Total" : 11,
"grocerie2Total" : 7,
"total" : 36
}
/* 3 */
{
"_id" : "22-08-2019",
"grocerie1" : [
{
"name" : "Cheese",
"total" : 4,
"count" : 2
},
{
"name" : "Rice",
"total" : 6,
"count" : 2
}
],
"grocerie2" : [
{
"name" : "Rice",
"total" : 9,
"count" : 3
}
],
"date" : "22-08-2019",
"grocerie1Total" : 10,
"grocerie2Total" : 9,
"total" : 19
}
I have the following array:
"devices": [
{
"_id": "HP Printer",
"count": 1
},
{
"_id": "55UA8990",
"count": 1
},
{
"_id": "Mac OS X 10.5",
"count": 1
},
{
"_id": "Nokia",
"count": 4
},
{
"_id": "Ubuntu Linux",
"count": 3
},
{
"_id": "LG handset",
"count": 1
},
{
"_id": "Samsung Home Audio/Video equipment",
"count": 1
},
{
"_id": "Generic Linux",
"count": 1
},
{
"_id": "Sony handset",
"count": 1
},
{
"_id": "Mac OS X 10.8",
"count": 12
},
{
"_id": "Linux Handheld",
"count": 1
},
{
"_id": "Symbian OS",
"count": 15
},
{
"_id": "RIM BlackBerry",
"count": 28
},
{
"_id": "Apple iPod",
"count": 1
},
{
"_id": "LG BL40",
"count": 1
},
{
"_id": "Slingbox",
"count": 67
},
{
"_id": "Windows XP",
"count": 60
},
{
"_id": "BlackBerry",
"count": 51
},
{
"_id": "Chrome OS",
"count": 7
},
{
"_id": "Eye-Fi Wireless Memory Card",
"count": 6
},
{
"_id": "Mac OS X 10.9",
"count": 62
},
{
"_id": "Mac OS X 10.10",
"count": 215
},
{
"_id": "Windows Vista",
"count": 4
},
{
"_id": "Windows Mobile OS",
"count": 213
},
{
"_id": "Windows 7/Vista",
"count": 394
},
{
"_id": "Mac OS X 10.11",
"count": 303
},
{
"_id": "Samsung TV",
"count": 1
},
{
"_id": "PlayStation Portable",
"count": 1
},
{
"_id": "Mac OS X",
"count": 755
},
{
"_id": "Windows 7",
"count": 612
},
{
"_id": "Apple iPad",
"count": 2597
},
{
"_id": "Ellipsis 8",
"count": 193
},
{
"_id": "Mac OS X 10.12",
"count": 550
},
{
"_id": "Nexus",
"count": 4657
},
{
"_id": "Windows 10",
"count": 772
},
{
"_id": "Windows 8",
"count": 1191
},
{
"_id": "Xbox 360",
"count": 39
},
{
"_id": "Mac OS X 10.6",
"count": 5
},
{
"_id": "Apple iPhone",
"count": 41039
},
{
"_id": "iOS",
"count": 25725
},
{
"_id": "Debian-based Linux",
"count": 9
},
{
"_id": null,
"count": 5291
},
{
"_id": "Mac OS X 10.7",
"count": 16
},
{
"_id": "Belkin Wireless Router",
"count": 1
},
{
"_id": "Windows",
"count": 1002
},
{
"_id": "Android",
"count": 51314
}
]
I'm trying to group all the values where the _id corresponds to the same os and add the count from each element, so I could get something like:
[
{
"label": "Windows",
"value": "9999"
},
{
"label": "Android",
"value": "8888"
},
{
"label": "iOS",
"value": "7777"
},
{
"label": "Macos",
"value": "10000"
},
{
"label": "Other",
"value": "5000"
}
]
I'm at a complete lost here, I would really appreciate some help and guidance.
Used Array.prototype.reduce and String.prototype.match for your scenario. Hope this helps.
var input = {"devices":[{"_id":"HP Printer","count":1},{"_id":"55UA8990","count":1},{"_id":"Mac OS X 10.5","count":1},{"_id":"Nokia","count":4},{"_id":"Ubuntu Linux","count":3},{"_id":"LG handset","count":1},{"_id":"Samsung Home Audio/Video equipment","count":1},{"_id":"Generic Linux","count":1},{"_id":"Sony handset","count":1},{"_id":"Mac OS X 10.8","count":12},{"_id":"Linux Handheld","count":1},{"_id":"Symbian OS","count":15},{"_id":"RIM BlackBerry","count":28},{"_id":"Apple iPod","count":1},{"_id":"LG BL40","count":1},{"_id":"Slingbox","count":67},{"_id":"Windows XP","count":60},{"_id":"BlackBerry","count":51},{"_id":"Chrome OS","count":7},{"_id":"Eye-Fi Wireless Memory Card","count":6},{"_id":"Mac OS X 10.9","count":62},{"_id":"Mac OS X 10.10","count":215},{"_id":"Windows Vista","count":4},{"_id":"Windows Mobile OS","count":213},{"_id":"Windows 7/Vista","count":394},{"_id":"Mac OS X 10.11","count":303},{"_id":"Samsung TV","count":1},{"_id":"PlayStation Portable","count":1},{"_id":"Mac OS X","count":755},{"_id":"Windows 7","count":612},{"_id":"Apple iPad","count":2597},{"_id":"Ellipsis 8","count":193},{"_id":"Mac OS X 10.12","count":550},{"_id":"Nexus","count":4657},{"_id":"Windows 10","count":772},{"_id":"Windows 8","count":1191},{"_id":"Xbox 360","count":39},{"_id":"Mac OS X 10.6","count":5},{"_id":"Apple iPhone","count":41039},{"_id":"iOS","count":25725},{"_id":"Debian-based Linux","count":9},{"_id":null,"count":5291},{"_id":"Mac OS X 10.7","count":16},{"_id":"Belkin Wireless Router","count":1},{"_id":"Windows","count":1002},{"_id":"Android","count":51314}]};
var output = input.devices.reduce(function(a, b) {
var match = b._id?b._id.match(/(Mac|Windows|Android|iOS)/):null;
match = match ? match[0] : 'Others';
a[match] = (a[match] || 0) + b.count;
return a;
}, {});
output = Object.keys(output).map(function(k){
return {
label: k,
value: output[k]
};
});
console.log(output);
Create an array of regex values each matching specific OS like .*windows.*.
Iterate your data array trying to match each entry's _id with the regex.
If it's a match add count value to value in output array. If it's not a match then add to "Other".
How you do it is up to you, it's just a general idea.
You could do something like:
var results = [];
devices.forEach(function(d) {
if(results.length === 0){ //shortcut for the first element
results.push({label:d._id, value: d.count});
} else {
var found = false;
for(var j =0; j < results.length; j++){
var i = results[j];
if(i.label === d._id){
found = true;
i.value += d.count;
results[j] = i;
}
});
if(!found) {
results.push({label:d._id, value: d.count});
}
}
});
return results;
This will iterate over the devices array and find the element in the array that matches and add the count to the value for that item in the array of results. If the item is not found, or it is the first item, a new object is pushed to the results array.
You could use an array with the grouping strings and use a hash table for counting.
var data = { devices: [{ _id: "HP Printer", count: 1 }, { _id: "55UA8990", count: 1 }, { _id: "Mac OS X 10.5", count: 1 }, { _id: "Nokia", count: 4 }, { _id: "Ubuntu Linux", count: 3 }, { _id: "LG handset", count: 1 }, { _id: "Samsung Home Audio/Video equipment", count: 1 }, { _id: "Generic Linux", count: 1 }, { _id: "Sony handset", count: 1 }, { _id: "Mac OS X 10.8", count: 12 }, { _id: "Linux Handheld", count: 1 }, { _id: "Symbian OS", count: 15 }, { _id: "RIM BlackBerry", count: 28 }, { _id: "Apple iPod", count: 1 }, { _id: "LG BL40", count: 1 }, { _id: "Slingbox", count: 67 }, { _id: "Windows XP", count: 60 }, { _id: "BlackBerry", count: 51 }, { _id: "Chrome OS", count: 7 }, { _id: "Eye-Fi Wireless Memory Card", count: 6 }, { _id: "Mac OS X 10.9", count: 62 }, { _id: "Mac OS X 10.10", count: 215 }, { _id: "Windows Vista", count: 4 }, { _id: "Windows Mobile OS", count: 213 }, { _id: "Windows 7/Vista", count: 394 }, { _id: "Mac OS X 10.11", count: 303 }, { _id: "Samsung TV", count: 1 }, { _id: "PlayStation Portable", count: 1 }, { _id: "Mac OS X", count: 755 }, { _id: "Windows 7", count: 612 }, { _id: "Apple iPad", count: 2597 }, { _id: "Ellipsis 8", count: 193 }, { _id: "Mac OS X 10.12", count: 550 }, { _id: "Nexus", count: 4657 }, { _id: "Windows 10", count: 772 }, { _id: "Windows 8", count: 1191 }, { _id: "Xbox 360", count: 39 }, { _id: "Mac OS X 10.6", count: 5 }, { _id: "Apple iPhone", count: 41039 }, { _id: "iOS", count: 25725 }, { _id: "Debian-based Linux", count: 9 }, { _id: null, count: 5291 }, { _id: "Mac OS X 10.7", count: 16 }, { _id: "Belkin Wireless Router", count: 1 }, { _id: "Windows", count: 1002 }, { _id: "Android", count: 51314 }] },
os = ["Windows", "Android", "iOS", "Mac OS", "Other"],
result = data.devices.reduce(function (hash) {
return function (r, a) {
var key = 'Other';
os.some(function (o) {
if (typeof a._id === 'string' && a._id.toLowerCase().indexOf(o.toLowerCase()) !== -1) {
key = o;
return true;
}
});
if (!hash[key]) {
hash[key] = { label: key, value: 0 };
r.push(hash[key]);
}
hash[key].value += a.count;
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }