Reorder JSON based on date using Jquery/JS - javascript

Thanks ahead for your help!
I'm trying to reorder some objects so the newest ordered product would be first. So looking at the data below, the new order should be (from newest to oldest) product2, product3, and then product1.
{
"candyResponse": {
"product1": {
"displayName": "Bubble Gum",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod1?$146$",
"orderDate": {
"time": "11/03/2018"
}
},
"product2": {
"displayName": "Chocolate",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod2?$146$",
"orderDate": {
"time": "03/05/2015"
}
},
"product3": {
"displayName": "Mints",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod3?$146$",
"orderDate": {
"time": "09/20/2017"
}
}
}
}
I tweaked the code from Sorting an array of JavaScript objects but I was not successful. Tried three ways...
candyResponse.sort(function(a, b) {
return parseFloat(a.time) - parseFloat(b.time);
});
candyResponse.sort(function(a, b) {
return parseFloat(a.orderDate) - parseFloat(b.orderDate);
});
candyResponse.sort(function(a, b) {
return parseFloat(a.orderDate.time) - parseFloat(b.orderDate.time);
});
Thanks again for your help!

candyResponse is an object, not an array - objects' property names are not reliably ordered, per the spec, so even if you did create a new object with the properties in the desired insertion order, it wouldn't be something to rely on.
Sort an array instead:
const candyResponse = {
"product1": {
"displayName": "Bubble Gum",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod1?$146$",
"orderDate": {
"time": "11/03/2018"
}
},
"product2": {
"displayName": "Chocolate",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod2?$146$",
"orderDate": {
"time": "03/05/2015"
}
},
"product3": {
"displayName": "Mints",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod3?$146$",
"orderDate": {
"time": "09/20/2017"
}
}
};
const getTime = ([_, product]) => {
return new Date(product.orderDate.time);
};
const sortedCandyArr = Object.entries(candyResponse)
.sort((a, b) => getTime(b) - getTime(a));
console.log(sortedCandyArr);

Well, you don't have an array of javascript objects, you just have a javascript object. That being said, you could do:
var data = {
"candyResponse": {
"product1": {
"displayName": "Bubble Gum",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod1?$146$",
"orderDate": {
"time": "11/03/2018"
}
},
"product2": {
"displayName": "Chocolate",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod2?$146$",
"orderDate": {
"time": "03/05/2015"
}
},
"product3": {
"displayName": "Mints",
"imageURL": "https://dummyimage.com/200x200/000/ffffff.png&text=prod3?$146$",
"orderDate": {
"time": "09/20/2017"
}
}
}
}
var sorted = Object.keys(data.candyResponse)
.sort((a, b) =>
new Date(data.candyResponse[a].orderDate.time).getTime() -
new Date(data.candyResponse[b].orderDate.time).getTime());
data.candyResponse = sorted.reduce((carry, current) => { carry[current] = data.candyResponse[current]; return carry; }, {});
console.log(data)

Related

Return additional properties using reduce and spread operator JS?

I am using the reduce function below to count how many times a players name is mentioned and then list them based on who was mentioned the most to the least.
I am trying to return the 2nd property [`${value.subtitles[0].name} + ${index}`] : value.subtitles[0].url with my object and sort it. However it is not sorting properly. When only returning the first property [value.title]: (acc[value.title] || 0) + 1, everything works as intended. But the second property is making it sort incorrectly. It is supposed to be sorting based on the title property value which is an integer of how many times that player was mentioned, from most to least. Why is this happening?
Thanks for the help!
const players = [
{
"title": "Mike",
"titleUrl": "https://mikegameplay",
"subtitles": [
{
"name": "Mike Channel",
"url": "https://channel/mike"
}
]
},
{
"title": "Cindy",
"titleUrl": "https://cindy",
"subtitles": [
{
"name": "Cindy Channel",
"url": "https://channel/cindy"
}
]
},
{
"title": "Mike",
"titleUrl": "https://mike",
"subtitles": [
{
"name": "Mike Channel",
"url": "https://channel/mike"
}
]
},
{
"title": "Haley",
"titleUrl": "https://Haley",
"subtitles": [
{
"name": "Haley Channel",
"url": "https://channel/haley"
}
]
},
{
"title": "Haley",
"titleUrl": "https://Haley",
"subtitles": [
{
"name": "Haley Channel",
"url": "https://channel/haley"
}
]
},
{
"title": "Haley",
"titleUrl": "https://Haley",
"subtitles": [
{
"name": "Haley Channel",
"url": "https://channel/haley"
}
]
}
]
const counts = players.reduce((acc, value, index) => ({
...acc,
[value.title]: (acc[value.title] || 0) + 1,
[`${value.subtitles[0].name} + ${index}`] : value.subtitles[0].url
}), {});
const sortedValues = [];
for (const value in counts) {
sortedValues.push([value, counts[value]]);
};
sortedValues.sort((a, b) => b[1] - a[1]);
console.log(sortedValues)
try this
var groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var pl = groupBy(players, "title");
console.log(pl);
let sortable = [];
for (var item in pl) {
sortable.push([item, pl[item].length, pl[item][0].subtitles[0].url]);
}
sortable.sort(function (a, b) {
return b[1] - a[1];
});
console.log(JSON.stringify(sortable));
result
[["Haley",3,"https://channel/haley"],["Mike",2,"https://channel/mike"],["Cindy",1,"https://channel/cindy"]]

Filter an nested Object with filter and map with JavaScript

I know that this is close to a duplicate but I can't get the code to work. I have an object that I need to filter and I'm currently trying to emulate the accepted as an answer the code at Javascript filtering nested arrays
My data object is:
[{
"project_num": "5R01DA012513-23",
"principal_investigators": [{
"profile_id": 2076451,
"full_name": "PK",
"title": ""
}]
},
{
"project_num": "5R01DK118529-03",
"principal_investigators": [{
"profile_id": 8590844,
"full_name": "HW",
"title": "PROFESSOR, SCIENTIFIC DIRECTOR"
}]
},
{
"project_num": "3R01AA025365-05S1",
"principal_investigators": [{
"profile_id": 8730036,
"full_name": "JJ",
"title": "ASSOCIATE PROFESSOR OF PSYCHIATRY"
}]
},
{
"project_num": "1R01HL163963-01",
"principal_investigators": [{
"profile_id": 2084037,
"full_name": "KH",
"title": "ASSOCIATE PROFESSOR"
},
{
"profile_id": 11309656,
"full_name": "AM",
"title": "RESEARCH ASSISTANT PROFESSOR"
}
]
},
{
"project_num": "5R25HL092611-15",
"principal_investigators": [{
"profile_id": 1886512,
"full_name": "CW",
"title": "P"
}]
}
]
and my JavaScript code is:
let payLoad = 1886512
const result = this.reporterData.map(t => {
const principal_investigators = t.principal_investigators.filter(d =>
d.profile_id === payLoad);
return { ...t,
principal_investigators
};
})
I need to pass in a profile_id as a payload and return the objects that will fill a data table.
The data can be 1000's of items and the principla_investigators can be multiple entries. When I use the code that I have it return all of the objects. Can someone point out my error? Thanks
You can try doing like this:
const result = this.reporterData.filter((t) => {
const principal_investigators = t.principal_investigators.filter((d) => d.profile_id === payLoad)
return (principal_investigators.length > 0)
})
I understand that you want an array with all the investigators matching that ID, right?
Try this:
const result = this.reporterData.reduce((previous, current) => {
if (current.principal_investigators) {
current.principal_investigators.forEach(pi => {
if (pi.profile_id === payLoad) {
previous.push(current)
}
});
}
return previous
}, [])
You can also do for loops with the same result:
const result = [];
for (project of this.reporterData) {
if (project.principal_investigators) {
for (pi of project.principal_investigators) {
if (pi.profile_id == payLoad) {
result.push(pi);
}
}
}
}

Sort array of objects based first on a subarray and then on dates (without splitting the array)

I have an array of objects that I want to sort based on whether or not they include a string.
I then want to sort those that do match the string by chronological order, and then the rest by chronological order.
So that
const role = waiter
const jobs = [
{
"date": "2021-09-30T00:00:00",
"role": [chef, porter]
},
{
"date": "2021-09-28T00:00:00",
"role": [waiter, chef]
},
{
"date": "2021-09-29T00:00:00",
"role": [waiter, chef]
},
{
"date": "2021-09-01T00:00:00",
"role": [chef]
},
]
Should become:
[
{
"date": "2021-09-28T00:00:00",
"role": [waiter, chef]
},
{
"date": "2021-09-29T00:00:00",
"role": [waiter, chef]
},
{
"date": "2021-09-01T00:00:00",
"role": [chef]
},
{
"date": "2021-09-30T00:00:00",
"role": [chef, porter]
},
]
So far the only solution I can find is to separate the array into two separate arrays. Sort them individually and then merge them back into one.
My current solution:
const arrOne = jobs
.filter((j) => j.role.includes(role))
.sort((a, b) =>
compareDesc(
a.date,b.date
)
);
const arrTwo = jobs
.filter((j) => !j.role.includes(role))
.sort((a, b) =>
compareDesc(
a.date,b.date
)
);
const finalArr = [...arrOne,...arrTwo]
Is there a more elegant solution?
Preferably one that doesn't require splitting the arrays into separate arrays?
You can just use .sort and put in the sort conditions (if both match role, then by date, if first only, it goes first, it second only, it goes first, if none, then by date):
const chef = 'chef';
const porter = 'porter';
const waiter = 'waiter';
const role = waiter;
const jobs = [
{
"date": "2021-09-30T00:00:00",
"role": [chef, porter]
},
{
"date": "2021-09-28T00:00:00",
"role": [waiter, chef]
},
{
"date": "2021-09-29T00:00:00",
"role": [waiter, chef]
},
{
"date": "2021-09-01T00:00:00",
"role": [chef]
}
]
console.log(jobs.sort((a, b) => {
if (a.role.includes(role) && b.role.includes(role)) {
return new Date(a.date) - new Date(b.date);
} else if (a.role.includes(role)) {
return -1;
} else if (b.role.includes(role)) {
return 1;
}
return new Date(a.date) - new Date(b.date);
}));
This should do it. first filter, then splice. the push found members to front
const role = 'waiter'
const jobs = [
{
"date": "2021-09-30T00:00:00",
"role": ['chef', 'porter']
},
{
"date": "2021-09-28T00:00:00",
"role": ['waiter', 'chef']
},
{
"date": "2021-09-29T00:00:00",
"role": ['waiter', 'chef']
},
{
"date": "2021-09-01T00:00:00",
"role": ['chef']
},
]
const jobFound = jobs.some(job => job.role.includes(role)); // filter the roles that match.
if (jobFound) {
const sortedJobs = jobs.filter((job) => job.role.includes(role)); // filter desired data
sortedJobs.sort((a, b) => a.date.localeCompare(b.date)); // sort by date
sortedJobs.forEach((job) => jobs.splice(jobs.indexOf(job), 1)); // splice the object that were matched
jobs.sort((a, b) => a.date.localeCompare(b.date)); // sort our original array
jobs.unshift(...sortedJobs); // push ordered members to front of array
}
console.log(jobs);

Wrap Properties of one Object to another - JavaScript

May I know if using reduce I can achieve the following where the properties of activatedItems and quarterItems are wrapped in one object i.e., modules.
{
"isExternalVisitor": false,
"modules": [
{
"moduleId": "e569da0e-44e6-4f75-96c4-bdd888678abd",
"code": "NEWQ2/SITENAME/2021-Q3-1",
"siteId": "10babdbe-5346-43e8-932a-4c7ae54dcb1b",
"activatedId": "2e03c658-3bbd-4332-bb1b-14fe56c7e753"
},
{
"moduleId": "588905b4-2c1d-49bf-a71f-84210405bc94",
"code": "NEWQ1/SITENAME/2021-Q1-2",
"siteId": "10babdbe-5346-43e8-932a-4c7ae54dcb1b",
"activatedId": "6c1691d2-7c37-4888-a446-9219fa9b9014"
}
],
"activatedItems": [
{
"activatedId": "2e03c658-3bbd-4332-bb1b-14fe56c7e753",
"stQuarterId": "b36d7e23-15e5-4f97-b52e-65757de4b264"
},
{
"activatedId": "6c1691d2-7c37-4888-a446-9219fa9b9014",
"stQuarterId": "01000f98-6470-440a-a833-95b199ab1f7a"
}
],
"quarterItems": [
{
"id": "b36d7e23-15e5-4f97-b52e-65757de4b264",
"checklistId": "8b479656-8cde-4bff-9c51-d5eca369bc76",
"fullName": "dsad",
"year": "2021-01-01T00:00:00",
"quarter": "2021-Q3",
"versions": 1
},
{
"id": "01000f98-6470-440a-a833-95b199ab1f7a",
"checklistId": "039f2584-1ca5-4ee3-b46f-cdf1887af7f6",
"fullName": "NEWQ1",
"year": "2021-01-01T00:00:00",
"quarter": "2021-Q1",
"versions": 2
}
]
}
This is the expected result where only one object has got all the data.
{
"isExternalVisitor": false,
"modules": [
{
"moduleId": "e569da0e-44e6-4f75-96c4-bdd888678abd",
"code": "NEWQ2/SITENAME/2021-Q3-1",
"siteId": "10babdbe-5346-43e8-932a-4c7ae54dcb1b",
"activatedId": "2e03c658-3bbd-4332-bb1b-14fe56c7e753",
"stQuarterId": "b36d7e23-15e5-4f97-b52e-65757de4b264",
"checklistId": "8b479656-8cde-4bff-9c51-d5eca369bc76",
"fullName": "dsad",
"year": "2021-01-01T00:00:00",
"quarter": "2021-Q3",
"versions": 1
},
{
"moduleId": "588905b4-2c1d-49bf-a71f-84210405bc94",
"code": "NEWQ1/SITENAME/2021-Q1-2",
"siteId": "10babdbe-5346-43e8-932a-4c7ae54dcb1b",
"activatedId": "6c1691d2-7c37-4888-a446-9219fa9b9014",
"stQuarterId": "01000f98-6470-440a-a833-95b199ab1f7a",
"checklistId": "039f2584-1ca5-4ee3-b46f-cdf1887af7f6",
"fullName": "NEWQ1",
"year": "2021-01-01T00:00:00",
"quarter": "2021-Q1",
"versions": 2
}
]
}
I tried the following and was able to merge them in one array, but however, the end result is not the same as above. Your kind help will be appreciated.
let modules = arr.modules;
let activatedItems = arr.activatedItems;
let quarterItems = arr.quarterItems;
let finalArr = [];
modules.forEach(module => {
activatedItems.forEach(item =>{
if(item.activatedId == module.activatedId)
{
quarterItems.forEach(quaItem => {
if(quaItem.id == item.stQuarterId){
finalArr.push(module);
finalArr.push(item);
finalArr.push(quaItem);
}
})
}
})
})
it seems you're just joining the arrays on index. If that's the case, a simple map will do! Just map over modules and use the index of the map callback function to grab the corresponding object from the other arrays.
const obj={isExternalVisitor:!1,modules:[{moduleId:"e569da0e-44e6-4f75-96c4-bdd888678abd",code:"NEWQ2/SITENAME/2021-Q3-1",siteId:"10babdbe-5346-43e8-932a-4c7ae54dcb1b",activatedId:"2e03c658-3bbd-4332-bb1b-14fe56c7e753"},{moduleId:"588905b4-2c1d-49bf-a71f-84210405bc94",code:"NEWQ1/SITENAME/2021-Q1-2",siteId:"10babdbe-5346-43e8-932a-4c7ae54dcb1b",activatedId:"6c1691d2-7c37-4888-a446-9219fa9b9014"}],activatedItems:[{activatedId:"2e03c658-3bbd-4332-bb1b-14fe56c7e753",stQuarterId:"b36d7e23-15e5-4f97-b52e-65757de4b264"},{activatedId:"6c1691d2-7c37-4888-a446-9219fa9b9014",stQuarterId:"01000f98-6470-440a-a833-95b199ab1f7a"}],quarterItems:[{id:"b36d7e23-15e5-4f97-b52e-65757de4b264",checklistId:"8b479656-8cde-4bff-9c51-d5eca369bc76",fullName:"dsad",year:"2021-01-01T00:00:00",quarter:"2021-Q3",versions:1},{id:"01000f98-6470-440a-a833-95b199ab1f7a",checklistId:"039f2584-1ca5-4ee3-b46f-cdf1887af7f6",fullName:"NEWQ1",year:"2021-01-01T00:00:00",quarter:"2021-Q1",versions:2}]};
const result = {
isExternalId: obj.isExternalId
};
result.modules = obj.modules.map((el, i) => ({
...el,
...obj.activatedItems[i],
...obj.quarterItems[i]
}));
console.log(result);

Transform nested array to D3 multiline time series

I'd like to transform a nested JSON object for a time series D3 multiline chart. I'd like to transform this:
[
{
"utc_date": "2012-12-13T00:00:00.000Z",
"data": {
"view": {
"count": 9061
},
"purchase": {
"count": 254
}
}
},
{
"utc_date": "2012-12-14T00:00:00.000Z",
"data": {
"view": {
"count": 17232
},
"purchase": {
"count": 539
}
}
},
{
"utc_date": "2012-12-15T00:00:00.000Z",
"data": {
"view": {
"count": 28783
},
"purchase": {
"count": 936
}
}
}]
to something like this (or better?)
[
{
"key": "view",
"data": [
{
"date": "2012-12-13T00:00:00.000Z",
"count": 9061
},
{
"date": "2012-12-14T00:00:00.000Z",
"count": 17232
},
{
"date": "2012-12-15T00:00:00.000Z",
"count": 28783
}
]
},
{
"key": "purchase",
"data": [
{
"date": "2012-12-13T00:00:00.000Z",
"count": 254
},
{
"date": "2012-12-14T00:00:00.000Z",
"count": 539
},
{
"date": "2012-12-15T00:00:00.000Z",
"count": 936
}
]
}
]
To be clear, "view" and "purchase" will not be known and are dynamic. So they shouldn't be hardcoded into the example.
But still wondering if there is any D3.js method or chain of methods to transform this data?
Assuming your original array is data, you could do something like this:
V=data.map(function(d){
w=d.data;
M=Array();
for (e in w) { // to loop for all parameters
M.push({"date":d.utc_date, "param":e,"count":w.view.count})
}
return M;
})
V=d3.merge(V)
V=d3.nest().key(function(d){return d.param}).entries(V);
V will hold your new data structure.
I am sure that this can be further improved.
EDIT
Perhaps you don't even need the d3.merge if you only append to another Array to begin with.
M=Array();
V=data.map(function(d){
w=d.data;
for (e in w) {
M.push({"date":d.utc_date, "param":e,"count":w.view.count})
}
})
V=d3.nest().key(function(d){return d.param}).entries(M);
I will let you experiement and see the difference in the performance and code structure.
Hope it helps
Just improving #Nikos answer below to cater for dynamic keys and, although it doesn't use a D3 method chain, this worked:
var result = [];
data.forEach(function(d) {
w = d.data;
for (var k in w) {
if (w.hasOwnProperty(k)) {
result.push({
"date":d.utc_date,
"type":k,
"count":w[k].count
});
}
}
});
JSFiddle here: http://jsfiddle.net/3umm391n/8/

Categories

Resources