Sort an array of objects by different keys - javascript

Hope you can help me with this question I have, that I'm pretty sure it's simple but I feel I'm missing some basic concepts here.
I have an array of objects like
[{
"id":"123",
"creationUser":"user1",
"updateUser":null,
"creationDate":1517495569000,
"updateDate":null,
"text":"Hello World"
},
{
"id":"543",
"creationUser":"user2",
"updateUser":"user3",
"creationDate":1517912985769,
"updateDate":1517921704448,
"text":"Hello people"
},
{
"id":"847",
"creationUser":"user 4",
"updateUser":null,
"creationDate":null,
"updateDate":1517913015110,
"text":"Text 1"
},
{
"id":"344",
"creationUser":"user 1",
"updateUser":"central",
"creationDate":1517912979283,
"updateDate":1517923926834,
"text":"Aloha!"
}]
As you can see there are some objects that doesn't have been updated so those values are set to null, but others have been updated, so what I would like to do is to order that array by creation date unless it has been updated, which mean that the updatedDate is the key value to compare this array.
I have tried:
let comments = conversation.sort(
(a,b) => {
if (a.updateDate){
return (a.creationDate - b.updateDate);
} else {
return (b.creationDate - a.updateDate);
}
});
But obviously it only works when comparing non updated objects. I'm pretty sure I'm missing something but I'm not sure, I also thought on splitting the array into updated array and non updated array and then merege it, but it sounds a bit hacky to me.
Please please, if you can give me a hint on this, it would be great!
Thanks a lot!

You could use logical OR || and take as default creationDate.
var array = [{ id: "123", creationUser: "user1", updateUser: null, creationDate: 1517495569000, updateDate: null, text: "Hello World" }, { id: "543", creationUser: "user2", updateUser: "user3", creationDate: 1517912985769, updateDate: 1517921704448, text: "Hello people" }, { id: "847", creationUser: "user 4", updateUser: null, creationDate: null, updateDate: 1517913015110, text: "Text 1" }, { id: "344", creationUser: "user 1", updateUser: "central", creationDate: 1517912979283, updateDate: 1517923926834, text: "Aloha!" }];
array.sort((a, b) => (a.updateDate || a.creationDate) - (b.updateDate || b.creationDate));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

So that make it so you use the defined dates by picking the one that is defined for each object.
var aDate = a.updateDate || a.creationDate
var bDate = b.updateDate || b.creationDate
return bDate - aDate

Evaluate the existence of the updateDate property first and if not exists, use the creationDate property:
var data =[{
"id":"123",
"creationUser":"user1",
"updateUser":null,
"creationDate":1517495569000,
"updateDate":null,
"text":"Hello World"
},
{
"id":"543",
"creationUser":"user2",
"updateUser":"user3",
"creationDate":1517912985769,
"updateDate":1517921704448,
"text":"Hello people"
},
{
"id":"847",
"creationUser":"user 4",
"updateUser":null,
"creationDate":null,
"updateDate":1517913015110,
"text":"Text 1"
},
{
"id":"344",
"creationUser":"user 1",
"updateUser":"central",
"creationDate":1517912979283,
"updateDate":1517923926834,
"text":"Aloha!"
}];
data.sort(function (a,b) {
var aDate = a.updateDate?a.updateDate:a.creationDate;
var bDate = b.updateDate?b.updateDate:b.creationDate;
return aDate - bDate;
});
console.log(data)

((a.updateDate || 0) - (b.updateDate || 0)) || a.creationDate - b.creationDate
That compares by creation date if both updateDates arent set, otherwise the updateSet comes first.

Related

IndexOf over a nested array response graph returning just []

I am trying to filter some articles from a graphql response, by articleTag. Se my structure below:
{
"id": "41744081",
"articleTitle": "text",
"articleContent": "text",
"categoryName": { "categoryName": "Company", "id": "38775744" },
"articleTags": [
{ "articleTag": "event", "id": "37056861" },
{ "articleTag": "car", "id": "37052481" },
]
},
{
"id": "41754317",
"articleTitle": "text",
"articleContent": "text",
"categoryName": { "categoryName": "Sales and Martketing", "id": "38775763" },
"articleTags": [{ "articleTag": "technology", "id": "37056753" }]
},
...
But when applying my function:
notificationFiltered () {
var articleResponse = this.response.allArticles;
var routeParam = this.$route.params.tagName; //contains the id of the tag
const filteredTag = articleResponse.filter((item) => {
return (item.articleTags.indexOf(routeParam) >= 0);
});
console.log(filteredTag);
},
When I'm "console.log" the result I get only a "[]". Not sure if is related with the way of query is being render, in the API I get the same formation but with this slightly difference
{
"data": {
"allArticles": [... the specify structure above]
}
}
while printing that with vue {{response.allArticles}} I just get the first structure, I think it shouldn't matter?
Thanks in advance for the advice
You won't be able to use indexOf for array of objects to find a matching object - only strict equality is needed, and that's hard to get in the reference land. Consider this:
const objs = [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'foo' } // whatever
];
const needle = { foo: 'baz' };
objs.indexOf(needle);
// -1
What? Yes, there's an object looking exactly like needle in that array - but it's a different object:
objs[1] === needle; // false
That's why indexOf just goes past that one - and gives out -1, a "not found" result.
What you should be able to use in this case is findIndex. Still you need to build the predicate to have a match. For example:
const objs = [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'foo' }
];
const needle = { foo: 'baz' };
objs.findIndex(el => JSON.stringify(el) === JSON.stringify(needle));
// 1
In this example, comparing results of JSON.stringify in the predicate function is a poor man's _.isEqual - just to illustrate the concept. What you should consider actually using in your code is either _.isEqual itself, or similar function available in toolkit of your choice.
Alternatively, you can just check for specific fields' values:
objs.findIndex(el => el.foo === needle.foo); // still 1
This will apparently find objects even if their other properties do not match though.

How to show object from array which includes current key?

I have an array with many objects like this:
"title": "Harry Potter and the Philosophers Stone",
"price": "7.99",
"image": "https://say-hi.me/wp-content/uploads/2015/12/Digital-Harry-Potter-1.jpg",
"id": 1,
"author": "J.K.Rowling",
"rating": 5,
"onTop": false
Some of these objects have onTop key with value true. So how i can show objects using method map ONLY with value true ?
that ?
const data =
[ { title: 'Harry Potter and the Philosophers Stone'
, price: '7.99'
, image: 'https://say-hi.me/wp-content/uploads/2015/12/Digital-Harry-Potter-1.jpg'
, id: 1
, author: 'J.K.Rowling'
, rating: 5
, onTop: false
}
, { title: 'xyz'
, price: '7.99'
, image: 'https://xyz.jpg'
, id: 1
, author: 'xyz'
, rating: 5
, onTop: true
}
]
const res = data.filter(e=>e.onTop)
console.log( res )
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use the lodash library here https://lodash.com/docs/4.17.15#filter
Then you can do
var books = [
{ 'title': 'doggo', 'onTop': true },
{ 'title': 'catto', 'onTop': false }
];
const onTopBooks = _.filter(books, function(o) { return o.onTop; });
which should return you a new array with
[{ title: 'doggo', onTop: true }]
I would not use the map method because it returns a value for each element in the array and you would need an additional loop to remove the null items you dont want. filter or some method similar like select will be better here.
Additionally, you could just do something even more basic like:
let onTopBooks = []
books.forEach( book => {
if (book.onTop) {
onTopBooks.push(book)
}
})
return onTopBooks

array difference in javascript

I know this will be so simple but I am trying this for two days so I finally decided to take help from you guys...
I have tried this probably the same question as mine but it is not giving me the answer.
ok so these are the two array
a = [{toNumber: "123", message: "Hi Deep "}, {toNumber: "321", message: "Test1"}]
b = [{toNumber: "321", message: "Test2"}, {toNumber: "123", message: "Hi Deep "}]
What I want is
diff = [{toNumber: "321", message: "Test2"}]
so quick help would be much appriciated.
So with your code you need to look at the other object and see if it has any keys that match. If it matches, you need to see if the message matches. So you can make a look up object that has the list of ids. You can than loop over your second array and see if they march.
var a = [
{toNumber: "123", message: "Hi Deep "},
{toNumber: "321", message: "Test1"}
]
var b = [
{toNumber: "321", message: "Test2"},
{toNumber: "123", message: "Hi Deep "}
]
// create the lookup from the first array
var lookup = a.reduce( function (lookUpObj, entryA) {
// set the object property with the toNumber property
lookUpObj[entryA.toNumber] = entryA.message
return lookUpObj
}, {})
// Now loop over the array and look for the differences
var diff = b.reduce(function (arr, entryB) {
// grab the entry from the lookup object we created
var orginalMessage = lookup[entryB.toNumber]
// if we do not have it listed OR the message is different
// add it to the list as changed.
if (!orginalMessage || orginalMessage !== entryB.message) {
arr.push(entryB)
}
return arr
}, [])
console.log(diff)
Now that will match any differences from a to b. If anything was removed in B that is not in A it will not be caught.
Where is the problem ???
const a =
[ { toNumber: "123", message: "Hi Deep " }
, { toNumber: "321", message: "Test1" }
]
const b =
[ { toNumber: "321", message: "Test2" }
, { toNumber: "123", message: "Hi Deep " }
]
const diff = b.filter(eB=>!a.some(eA=>( eA.toNumber===eB.toNumber
&& eA.message===eB.message )))
document.write( JSON.stringify( diff ) )

Javascript copy no repeat object data taht have same property from array

I have an arrry that has 100 object and it has same property code
Data = [
{yera:"2019", name:"saif", topic:"oil"},
{yera:"2018", name:"abc", topic: "oil"},
{yera:"2018", name:"jorj", topic:"energy"},
{yera:"2017", name:"tom", topic:"gas"},
{yera:"2016",name:"saif",topic:"electricity "},
{yera:"2014", name:"gour",topic:"oil"},
Assuming you want to remove duplicates from the array of objects based on a key of that object, the code below will achieve that.
var data = [
{yera:"2019", name:"saif", topic:"oil"},
{yera:"2018", name:"abc", topic: "oil"},
{yera:"2018", name:"jorj", topic:"energy"},
{yera:"2017", name:"tom", topic:"gas"},
{yera:"2016",name:"saif",topic:"electricity "},
{yera:"2014", name:"gour",topic:"oil"}
]
function getUniqueData(originalData, keyToCheckForUniqueness) {
var store = {};
var output = [];
originalData.forEach(function (ob) {
var val = ob[keyToCheckForUniqueness];
if (!store[val]) {
store[val] = [ob];
} else {
store[val].push(ob);
}
});
// at this point your store contains all the repeating data based on that property value
// console.log(store);
// now emit single values from that store;
// this logic can be based on any criterion, I chose the first element of the array - it may change depending on the order of values in input
Object.keys(store).forEach(function (key) {
var uniqueValArray = store[key];
var uniqueVal = uniqueValArray[0]; // take the first entry
output.push(uniqueVal);
});
return output;
}
getUniqueData(data, "topic");
This will achieve what I think you want to figure out. A word of advice - Don't let people think when you ask them for help. Second, try writing the logic for yourself. Post your non-working solution and ask, where you made a mistake - rather than asking. Given your rep, welcome to SO. Hope you a great learning experience.
Assuming, you want unique values for a given property of the objects, you could map that value and take a Set for getting unique values.
function getUnique(array, key) {
return Array.from(new Set(array.map(({ [key]: v }) => v)));
}
var array = [{ year: "2019", name: "grace", topic: "oil" }, { year: "2018", name: "grace", topic: "oil" }, { year: "2018", name: "jane", topic: "energy" }, { year: "2017", name: "tom", topic: "gas" }, { year: "2016", name: "jane", topic: "electricity" }, { year: "2014", name: "gour", topic: "oil" }];
console.log(getUnique(array, 'year'));
console.log(getUnique(array, 'name'));
console.log(getUnique(array, 'topic'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

javascript - search for string in array of objects

I would like to search for a string in array of objects and returns objects that matches. Trying to use es6 here.
Please find below code:
// set of keys
const defConfigs = [{
title: "Id",
key: "id"
},
{
title: "Tenant",
key: "tenant"
},
{
title: "Opened",
key: "opened"
},
{
title: "Title",
key: "title"
},
{
title: "Status",
key: "status"
},
{
title: "Priority",
key: "priority"
}
];
// items as array of objects
const items = [{
id: "INC000000004519",
title: "Follow-up after INC000000004507",
description: null,
urgency: "4-Low",
severity: "4-Minor/Localized"
},
{
id: "INC000000004515",
title: "network drop:↵Network Element CVU042_Johnstown get unsynchronized↵Network Element CVU043_Redman",
description: "Client network drop since 08:51 until 09:06, pleas…ork Element CVU045_North_Salem get unsynchronized",
urgency: "3-Medium",
severity: "3-Moderate/Limited"
},
{
id: "INC000000004088",
title: "not able to schedule GPEH in ABC",
description: "Contact: abc#xyz.com↵+14692669295↵…WCDMA, we are not able to schedule GPEH in ABC. I",
urgency: "4-Low",
severity: "4-Minor/Localized"
},
{
id: "INC000000004512",
title: "SR Updated - P3 - 2018-0427-0305 - xyz TELECOMMUNICATIONS ROMANIA S.R.L - Lost the mng connect",
description: null,
urgency: "4-Low",
severity: "4-Minor/Localized"
},
{
id: "INC000000004414",
title: "Acme incident 1 title",
description: "Acme incident 1 description",
urgency: "2-High",
severity: "1-Extensive/Widespread"
}
];
// trying to search for string in keys defined in defConfigs
items.filter(item =>
defConfigs.forEach((def) => {
if (def.key in item) {
return (item[def.key].toString().toLowerCase().match('low').length > 1);
}
}));
// always throws an error Uncaught TypeError: Cannot read property 'length' of null
console.log(items);
Here, there are 3 objects with string "low" and I expect the code to return the first item (where the "title" is "Follow-up after"); but match never returns.
How do I search for a string in array of objects and return those objects as a result ?
If you look closely you will notice that:
You do not check if .match matched (it returns null on no match; testing for null.length will throw an error)
You are checking match.length > 1... the syntax you are using will return an array with exactly one item or null
You are missing the return statement for .filter
You do not assign the return value of .filter to any variable
Here is what you need to do:
var filteredItems = items.filter(function (item) {
return defConfigs.some(function (def) {
return (def.key in item)
? item[def.key].toString().toLowerCase().match('low') !== null
: false;
});
});
console.log(filteredItems);
String.prototype.match() function will return null if there are no matches, therefore you need check this case. Next you could use Array.prototype.some() function to verify that at least one item in array is fulfilling your condition. For example:
items.filter(item =>
// check if at least one key from `defConfigs` on `item` matches 'low'
defConfigs.some((def) => {
if (def.key in item) {
const matched = item[def.key].toString().toLowerCase().match('low')
// return true if item matched
return !!matched
}
// match not found by default
return false
}));
String.prototype.match() will return null when no match found. You should strictly compare match result to null if you want it to work.
You should take a look at Array.prototype.filter. It returns a new array and won't modify the reference passed as argument, your original items are safe (for now).
In your if statement, if (def.key in item), it will check if the value of def.key is equal to the name of an attribute in item. To accomplish what you were thinking of doing, see the comments in the code below:
// set of keys
const defConfigs = [{title: "Id", key: "id"},
{title: "Tenant", key: "tenant"},
{title: "Opened", key: "opened"},
{title: "Title", key: "title"},
{title: "Status", key: "status"},
{title: "Priority", key: "priority"}];
// items as array of objects
const items = [{id: "INC000000004519", title: "Follow-up after INC000000004507", description: null, urgency: "4-Low", severity: "4-Minor/Localized"},
{id: "INC000000004515", title: "network drop:↵Network Element CVU042_Johnstown get unsynchronized↵Network Element CVU043_Redman", description: "Client network drop since 08:51 until 09:06, pleas…ork Element CVU045_North_Salem get unsynchronized", urgency: "3-Medium", severity: "3-Moderate/Limited"},
{id: "INC000000004088", title: "not able to schedule GPEH in ABC", description: "Contact: abc#xyz.com↵+14692669295↵…WCDMA, we are not able to schedule GPEH in ABC. I", urgency: "4-Low", severity: "4-Minor/Localized"},
{id: "INC000000004512", title: "SR Updated - P3 - 2018-0427-0305 - xyz TELECOMMUNICATIONS ROMANIA S.R.L - Lost the mng connect", description: null, urgency: "4-Low", severity: "4-Minor/Localized"},
{id: "INC000000004414", title: "Acme incident 1 title", description: "Acme incident 1 description", urgency: "2-High", severity: "1-Extensive/Widespread"}];
// trying to search for string in keys defined in defConfigs
items.filter(item =>
defConfigs.forEach((def) => {
//iterate through all attributes in the object
for(var key in item){
//check if the attribute exists, if it has the method 'indexOf' (if it's a string), and that it has def.key in the string
if (item[key] && item[key].indexOf && item[key].indexOf(def.key)!= -1) {
//match only accepts regular expressions which are signified in JS by enclosing the expression with forward slashes
return (item[def.key].toString().toLowerCase().match(/low/).length >1);
}
}
}));
The word "low" is found only in the urgency attribute and your defConfigs array don't have this field
So after you add it to the array do the following :
let newItems=items.filter(item => {
let count= defConfigs.reduce((acc, def) => {
if (def.key in item) {
let arr = item[def.key].toString().toLowerCase().match(/low/gi)
return acc + (arr ? 1 : 0);
}
else {
return acc;
}
}, 0)
return count >0
});
console.log(newItems);
So first define a new variable for the filtered data newItems
Then i used the reduce function to get if there is any match in the whole object
lastly used the regular expression /low/gi in the match function

Categories