I have an array below like this
[
{
"Date": "2020-07",
"data": [
{
"id": "35ebd073-600c-4be4-a750-41c4be5ed24a",
"Date": "2020-07-03T00:00:00.000Z",
"transactionId": "13",
"transactionType": "Payment",
"amount": 1500
}
]
},
{
"Date": "2020-07",
"data": [
{
"id": "4e126519-e27b-4e82-bb81-689c7dc63c9b",
"Date": "2020-07-02T00:00:00.000Z",
"transactionId": "4",
"transactionType": "Payment",
"amount": 1000
}
]
},
{
"Date": "2020-06",
"data": [
{
"id": "646d6497-9dea-4f27-896e-a45d97a252ea",
"Date": "2020-06-04T00:00:00.000Z",
"transactionId": "14",
"transactionType": "Payment",
"amount": 1500
}
]
},
{
"Date": "2020-06",
"data": [
{
"id": "cf44e27f-2111-462d-b3bd-420a193745b8",
"Date": "2020-06-02T00:00:00.000Z",
"transactionId": "5",
"transactionType": "Payment",
"amount": 1000
}
]
}
]
Here there is key Date and there are two values for the same date key. Now I want if Date is same then data array record should merged.
So i expect output as
[
{
"Date": "2020-07",
"data": [
{
"id": "35ebd073-600c-4be4-a750-41c4be5ed24a",
"Date": "2020-07-03T00:00:00.000Z",
"transactionId": "13",
"transactionType": "Payment",
"amount": 1500
},
{
"id": "4e126519-e27b-4e82-bb81-689c7dc63c9b",
"Date": "2020-07-02T00:00:00.000Z",
"transactionId": "4",
"transactionType": "Payment",
"amount": 1000
}
]
},
{
"Date": "2020-06",
"data": [
{
"id": "646d6497-9dea-4f27-896e-a45d97a252ea",
"Date": "2020-06-04T00:00:00.000Z",
"transactionId": "14",
"transactionType": "Payment",
"amount": 1500
},
{
"id": "cf44e27f-2111-462d-b3bd-420a193745b8",
"Date": "2020-06-02T00:00:00.000Z",
"transactionId": "5",
"transactionType": "Payment",
"amount": 1000
}
]
}
]
Please tell me best-optimized way of doing it ?
You can use a dictionary and easily check if the key already exists and then append the new data, otherwise you will add the date as a new key.
var dict = {};
if (!("xxxx-xx" in dict)){ //if the key is not the dict
dict["xxxx-xx"] = [{ //we are storing an array because we want to add other later
id: "....",
transactionId: "..."
//etc...
}]
}
else { //if the key already exists, we push new data to the array
dict["xxxx-xx"].push({ //you can use push because is an array of objects
id: "....",
transactionId: "..."
//etc...
})
}
I hope that it can be helpful. An array would be less convenient to check if a key already exists and to avoid duplicates (by default with dict/object).
arr = your data set
obj = this will be your output
arr.forEach((elem) => {
if(obj[elem.Date]) {
obj[elem.Date].data.push(elem.data);
} else {
obj[elem.Date] = {
data: [elem.data]
}
}
});
First you have to group that array of objects by property Date. And iterate that grouped by key-value pairs of [Date, groupsByDate] then grab data from each group
const res = _.chain(data)
.groupBy("Date")
.toPairs()
.map(([key, value]) => ({
Date: key,
data: _.flatMap(value, "data"),
}))
.value()
Full code
const data = [
{
Date: "2020-07",
data: [
{
id: "35ebd073-600c-4be4-a750-41c4be5ed24a",
Date: "2020-07-03T00:00:00.000Z",
transactionId: "13",
transactionType: "Payment",
amount: 1500,
},
],
},
{
Date: "2020-07",
data: [
{
id: "4e126519-e27b-4e82-bb81-689c7dc63c9b",
Date: "2020-07-02T00:00:00.000Z",
transactionId: "4",
transactionType: "Payment",
amount: 1000,
},
],
},
{
Date: "2020-06",
data: [
{
id: "646d6497-9dea-4f27-896e-a45d97a252ea",
Date: "2020-06-04T00:00:00.000Z",
transactionId: "14",
transactionType: "Payment",
amount: 1500,
},
],
},
{
Date: "2020-06",
data: [
{
id: "cf44e27f-2111-462d-b3bd-420a193745b8",
Date: "2020-06-02T00:00:00.000Z",
transactionId: "5",
transactionType: "Payment",
amount: 1000,
},
],
},
]
const res = _.chain(data)
.groupBy("Date")
.toPairs()
.map(([key, value]) => ({
Date: key,
data: _.flatMap(value, "data"),
}))
.value()
console.log(JSON.stringify(res, null, 2))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.20/lodash.min.js"></script>
Related
I have the following array
[ {
"contactId": "a87d096gd5fuop",
"firstName": "John Doe",
"registrationTypes": {
"selectedOptions": [
{
}
],
"subTotal": 1620.003
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"events": {
"selectedOptions": [
{
"id": "1",
"name": "T1",
"value": "4550006:3",
},
{
"id": "2",
"name": "T2",
"value": "4550005:3",
},
{
"id": "3",
"name": "T3",
"value": "4550003:3",
}
],
"subTotal": 135.003
},
"freeNetworkingFunctions": {
},
"total": 1755.0059999999999
},
{
"contactId": "a097f",
"firstName": "David",
"registrationTypes": {
"selectedOptions": [
{}
],
"subTotal": 899.998
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"member": {
"selectedOptions": [
{
}
],
"subTotal": 228.8
},
"events": {
"selectedOptions": [
{
"id": "4",
"name": "T4",
"value": "4550002:2",
},
{
"id": "5",
"name": "T5",
"value": "4550001:2",
},
{
"id": "6",
"name": "T6",
"value": "4550003:2",
}
],
"subTotal": 135.003
},
"total": 1263.801
}
]
From the above array, I want to extract events, loop all the data and get only values. So my new array should be something like this:
[ {
"contactId": "a87d096gd5fuop",
"firstName": "John Doe",
"registrationTypes": {
"selectedOptions": [
{
}
],
"subTotal": 1620.003
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"events": [
"4550006:3"
"4550005:3",
"4550003:3",
],
},
"freeNetworkingFunctions": {
},
"total": 1755.0059999999999
},
{
"contactId": "a097f",
"firstName": "David",
"registrationTypes": {
"selectedOptions": [
{}
],
"subTotal": 899.998
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"member": {
"selectedOptions": [
{
}
],
"subTotal": 228.8
},
"events": [
"4550004:2"
"4550008:3",
"4550003:3",
],
"subTotal": 135.003
},
"total": 1263.801
}
]
So it should return the original array, however, events value data should be in one array.
var arr = [];
var r(var i=0;i<data.length;i++){
data.push(arr[i].value);
}
var newData = [...data, arr]
However, this doesn't work. Any help would be highly appreciated.
Use map twice - once on the dataset to iterate over the objects, and within that map to get an array of values from the selectedOptions.
const data=[{contactId:"a87d096gd5fuop",firstName:"John Doe",registrationTypes:{selectedOptions:[{}],subTotal:1620.003},foo1:{selectedOptions:[],subTotal:0},events:{selectedOptions:[{id:"1",name:"T1",value:"4550006:3"},{id:"2",name:"T2",value:"4550005:3"},{id:"3",name:"T3",value:"4550003:3"}],subTotal:135.003},freeNetworkingFunctions:{},total:1755.0059999999999},{contactId:"a097f",firstName:"David",registrationTypes:{selectedOptions:[{}],subTotal:899.998},foo1:{selectedOptions:[],subTotal:0},member:{selectedOptions:[{}],subTotal:228.8},events:{selectedOptions:[{id:"4",name:"T4",value:"4550002:2"},{id:"5",name:"T5",value:"4550001:2"},{id:"6",name:"T6",value:"4550003:2"}],subTotal:135.003},total:1263.801}];
const out = data.map(obj => {
// Destructure the selected options from the
// rest of each object
const { events: { selectedOptions }, ...rest } = obj;
// `map` over the options to just get an array of values
const events = selectedOptions.map(option => {
return option.value;
});
// Return a new object with the new events property
// combined with the other properties again
return { ...rest, events };
});
console.log(out);
Additional documentation
Destructuring assignment
Rest parameters
Spread syntax
I have this Object which I want to restructure as shown in the desired output below. The IngriId in desired output is just Date.now() I am struggling to rearrange this it seems impossible to me .Can this be done in javascript because I am very new to it and I am finding it hard to implement?
Input:
const Shopping = {
"meatsOutput": [
{
"val": "Chicken breast"
}
],
"spicesOutput": [
{
"amount": "½ tsp",
"val": "paprika"
}
],
"dairyOutput": [
{
"amount": "1/2 Cup",
"val": "yogurt"
},
{
"amount": "1/2 teaspoon",
"val": "heavy cream"
}
]
}
Desired Output:
const ShoppingList = [
{
"data": [{
"value": "Chicken breast",
"ingrId": "202237423fm16787",
}],
"name": "meatsOutput",
},
{
"data": [{
"amount": "½ tsp",
"value": "paprika",
"ingrId": "20223742381r787",
}],
"name": "spicesOutput",
},
{
"data": [{
"amount": "1/2 Cup",
"value": "yogurt",
"ingrId": "202237423816787",
}, ],
"name": "dairyOutput",
}
]
Using Object.entries, you can generate the [key, value] pair array, and then, using Array.prototype.map, you can change that array to the result you want.
const input = {
"meatsOutput": [{
"val": "Chicken breast"
}],
"spicesOutput": [{
"amount": "½ tsp",
"val": "paprika"
}],
"dairyOutput": [{
"amount": "1/2 Cup",
"val": "yogurt"
},
{
"amount": "1/2 teaspoon",
"val": "heavy cream"
}
]
};
const result = Object.entries(input).map(([key, value]) => ({
name: key,
data: value.map((item) => ({
...item,
ingrId: Date.now()
}))
}));
console.log(result);
I am trying to get data from JSON :
{
"data": {
"Country": [
{
"Area": "Urban",
"Date": "2019-10-14T12:14:20.170Z",
"income": [
{
"amount": "33",
"currency": "USD"
},
{
"amount": "10",
"currency": "INR"
}
],
"expenditure": [
{
"amount": "5",
"currency": "INR"
}
],
"tax": [
{
"amount": "10",
"currency": "USD"
},
{
"amount": "10",
"currency": "INR"
}
]
},
{
"Area": "Rural",
"Date": "2019-10-14T12:14:20.170Z",
"income": [
{
"amount": "2",
"currency": "USD"
},
{
"amount": "20",
"currency": "INR"
}
],
"loan": [
{
"amount": "5",
"currency": "INR"
}
],
"tax": [
{
"amount": "10",
"currency": "USD"
},
{
"amount": "50",
"currency": "INR"
}
]
}
]
}
}
I want to have a common object which hold data with all unique key such as income,expenditure and then sum the amount which has same currency.
Need result as below format:
{
"Area": "combined",
"income": [
{
"amount": "35",
"currency": "USD"
},
{
"amount": "30",
"currency": "INR"
}
],
"expenditure": [
{
"amount": "5",
"currency": "INR"
}
],
"loan": [
{
"amount": "5",
"currency": "INR"
}
],
"tax": [
{
"amount": "20",
"currency": "USD"
},
{
"amount": "60",
"currency": "INR"
}
]
}
If tried with map and reduce but i can't able to some without using if else statement to check for if value exists inside object is present or not and then do operation.
I tried with below approach:
jsonResponse.reduce(
// common_keys passing as hardcoded till loan ,tax etc
(result, { loan,tax}) => {
forEach(tax, value => {
const taxObj = find(result.tax, ['currency', value.currency]);
!taxObj ? result.tax.push(value) : taxObj.amount = Number(taxObj.amount) + Number(value.amount);
});
forEach(loan, value => {
const loanObj = find(result.loan, [
'currencyCode',
value.currency,
]);
!loanObj ? result.loan.push(value): loanObj.amount = Number(loanObj.amount) + Number(value.amount);
});
//repeating for other too
return result;
}
With all same currencyCode, you could reduce the array and the nested arrays as well.
var data = { data: { Country: [{ Area: "Urban", Date: "2019-10-14T12:14:20.170Z", income: [{ amount: "33", currencyCode: "USD" }, { amount: "10", currencyCode: "INR" }], expenditure: [{ amount: "5", currencyCode: "INR" }], tax: [{ amount: "10", currencyCode: "USD" }, { amount: "10", currencyCode: "INR" }] }, { Area: "Rural", Date: "2019-10-14T12:14:20.170Z", income: [{ amount: "2", currencyCode: "USD" }, { amount: "20", currencyCode: "INR" }], loan: [{ amount: "5", currencyCode: "INR" }], tax: [{ amount: "10", currencyCode: "USD" }, { amount: "50", currencyCode: "INR" }] }] } },
result = data.data.Country.reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => {
if (!Array.isArray(v)) return;
v.reduce((q, { amount, currencyCode }) => {
var temp = q.find(t => t.currencyCode === currencyCode);
if (!temp) q.push(temp = { amount: 0, currencyCode });
temp.amount = (+temp.amount + +amount).toString();
return q;
}, r[k] = r[k] || []);
});
return r;
}, { "Area": "combined" });
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am trying to traverse the data according to the show array and print the data to see if it is correct. To traverse the list array corresponding to the show array as follows
I want the effect as follows:
[
{
"name": "A",
"age": "10",
},
{
"name": "B",
"age": "20",
}
]
const data = [{
"code": "200",
"msg": "success",
"data": {
"list": [{
"name": "A",
"age": "10",
"logo": "aa.png",
"note": "aa"
}, {
"name": "B",
"age": "20",
"logo": "bb.png",
"note": "bb"
}],
"show": [
"name",
"age"
]
}
}]
function init() {
data.map(res => {
if (res.code == 200) {
console.log(res.data.list)
}
})
}
init();
By iterating show (rather than hard-coding name and age), this code would work also if you change the structure of your template:
const data = [{
"code": "200",
"msg": "success",
"data": {
"list": [{
"name": "A",
"age": "10",
"logo": "aa.png",
"note": "aa"
}, {
"name": "B",
"age": "20",
"logo": "bb.png",
"note": "bb"
}],
"show": [
"name",
"age"
]
}
}];
var ans = data[0].data.list.map(item => {
var curr = {};
data[0].data.show.forEach(prop => {
curr[prop] = item[prop];
});
return curr;
});
console.log(ans);
You can use reduce in a shorter way:
const data = [
{
code: "200",
msg: "success",
data: {
list: [
{
name: "A",
age: "10",
logo: "aa.png",
note: "aa"
},
{
name: "B",
age: "20",
logo: "bb.png",
note: "bb"
}
],
show: ["name", "age"]
}
}
];
console.log(data[0].data.list.map(x =>
data[0].data.show.reduce((p, c) => ((p[c] = x[c]), p), {})
));
const data = [{
"code": "200",
"msg": "success",
"data": {
"list": [{
"name": "A",
"age": "10",
"logo": "aa.png",
"note": "aa"
}, {
"name": "B",
"age": "20",
"logo": "bb.png",
"note": "bb"
}],
"show": [
"name",
"age"
]
}
}];
function init() {
data.map(res => {
if (res.code == 200) {
console.log(res.data.list.map(function(listValue) {
var ret = {};
res.data.show.forEach(function(idx) {
ret[idx] = listValue[idx]
});
return ret;
}));
}
})
}
init();
You can use .map on your data and return false if the code isn't 200, if it is 200, you can return a mapped version of your list array. You can map this array to a subset of each object in your list. The subset is defined by your show array, and so you can use .reduce() on this array to build your mapped object.
See example below:
const data = [{
"code": "200",
"msg": "success",
"data": {
"list": [{
"name": "A",
"age": "10",
"logo": "aa.png",
"note": "aa"
}, {
"name": "B",
"age": "20",
"logo": "bb.png",
"note": "bb"
}],
"show": [
"name",
"age"
]
}
}];
function init() {
return data.map(res => {
if (res.code == 200) {
return res.data.list.map((obj) => {
return res.data.show.reduce((acc, prop) => ({...acc, [prop]: obj[prop]}), {});
});
}
return false;
}).filter(Boolean); // filter out any `false` returns
}
console.log(init());
Alternatively, a better approach than mapping your original data would be to use .reduce(). This will create a one-dimensional array of results:
const data = [{
"code": "200",
"msg": "success",
"data": {
"list": [{
"name": "A",
"age": "10",
"logo": "aa.png",
"note": "aa"
}, {
"name": "B",
"age": "20",
"logo": "bb.png",
"note": "bb"
}],
"show": [
"name",
"age"
]
}
},
{
"code": "200",
"msg": "success",
"data": {
"list": [{
"name": "C",
"age": "30",
"logo": "aa.png",
"note": "aa"
}, {
"name": "D",
"age": "40",
"logo": "bb.png",
"note": "bb"
}],
"show": [
"name",
"age"
]
}
}];
function init() {
return data.reduce((acc, res) => {
if (res.code == 200) {
return [...acc, ...res.data.list.map((obj) => {
return res.data.show.reduce((acc, prop) => ({...acc, [prop]: obj[prop]}), {});
})];
}
return acc;
}, []);
}
console.log(init());
If you want to show only name and age as
[
{
"name": "A",
"age": "10",
},
{
"name": "B",
"age": "20",
}
]
Array.map can be used
and then you can write your code this way
const data = [
{
code: '200',
msg: 'success',
data: {
list: [
{
name: 'A',
age: '10',
logo: 'aa.png',
note: 'aa'
},
{
name: 'B',
age: '20',
logo: 'bb.png',
note: 'bb'
}
],
show: ['name', 'age']
}
}
]
function init() {
data.map(res => {
if (res.code == 200) {
console.log(
res.data.list.map(item => {
return {
name: item.name,
age: item.age
}
})
)
}
})
}
init()
Does this answer your question?
Good day, I've spent 2 - 3 hours just to get this working,
so I have this controller.js code:
const b_name = req.params.b;
const m_name = req.params.m;
const result = await cinemaDB.getcinemasbranchesmovies(model, {'details.branches_name': b_name, 'details.movies_name': m_name});
and this db.js code:
/** Get branches's movies by _id */
module.exports.getcinemasbranchesmovies =
async(model, query) => {
return new Promise((resolve, reject) => {
// console.log("branches: " + b_name + "movies: "+ m_name);
if (!query) {
query = {};
}
console.log("branches: ", query);
model.find(query)
.then(res => {
console.log("branches: ", res);
resolve(res);
})
.catch(err => {
reject(err);
console.log(err);
throw err;
});
});
}
and this route.js code:
server.get("/api/cinemas/getcbm/:b/:m",controller.getcinemasbranchesmovies);
EDIT! If you put it in a query:
model.find({'details.branches_name': "Evia", 'details.movies_name': "Greatest"})
now this is the JSON result:
{
"success": true,
"status": "OK",
"data": [
{
"_id": "5ab49348c356c713a836cc15",
"cinemas_name": "Cinemas 3",
"__v": 0,
"details": [
{
"price": 350,
"movies_name": "Black Panther",
"branches_name": "Bataan",
"_id": "5ab49348c356c713a836cc16",
"time": [
"1",
"2",
"3"
]
},
{
"branches_name": "Bataan",
"movies_name": "Black Panther",
"price": 350,
"_id": "5ab494b2c0a83c28e874ace9",
"time": [
"1",
"2",
"3"
]
},
{
"branches_name": "Bataan",
"movies_name": "Black Panther",
"price": 350,
"_id": "5ab495a9d0bebb3d4c26c086",
"time": [
"1",
"2",
"3"
]
},
{
"branches_name": "Bataan",
"movies_name": "December Avenue",
"price": 350,
"_id": "5ab495c5d0bebb3d4c26c087",
"time": [
"1",
"2",
"3"
]
},
{
"branches_name": "Taguig",
"movies_name": "December Avenue",
"price": 350,
"_id": "5ab49d4b2b0ce727dc9a2a07",
"time": [
"1",
"2",
"3"
]
},
{
"branches_name": "Evia",
"movies_name": "December Avenue",
"price": 350,
"_id": "5ab49d522b0ce727dc9a2a08",
"time": [
"1",
"2",
"3"
]
},
{
"branches_name": "Evia",
"movies_name": "Greatest",
"price": 350,
"_id": "5ab4a0e397ca122e8005c19f",
"time": [
"1",
"2",
"3"
]
}
]
}
]
}
Now what I need only is this value to be displayed:
{
"success": true,
"status": "OK",
"data": [
{
"_id": "5ab49348c356c713a836cc15",
"cinemas_name": "Cinemas 3",
"__v": 0,
"details": [
{
"branches_name": "Evia",
"movies_name": "Greatest",
"price": 350,
"_id": "5ab4a0e397ca122e8005c19f",
"time": [
"1",
"2",
"3"
]
}
]
}
]
}
So all in all, I want only to display the specific data I've inputted inside the query of find.
I do search it on google first, but I can't comprehend the way they code it.
So yeah, expanding my comprehension on google, I get it done by using the aggregate function.
replacing model.find -> model.aggregate
it's query is something like:
model.aggregate({$unwind:"$details"},
{
$match:{
"details.branches_name": query1,
"details.movies_name": query2
}
}
)
I hope someone helps by this :D