Check array of objects in lodash for property value - javascript

Given the following
var content = [{
"set_archived": false,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2016-12-01T18:23:29.743333Z",
"created": "2016-12-01T18:23:29.743333Z",
"archived": false
}]
},
{
"set_archived": true,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2017-01-30T19:42:29.743333Z",
"created": "2017-01-30T19:42:29.743333Z",
"archived": false
}]
}
];
Using Lodash, how would I determine if either set_archived or something.archived in the array of objects is equal to true?
So in this case, because the second object has set_is_archived that is true, then the expected response should be true. If all items are false in either object, then the response should be false.

Just use:
_.filter(content, o => o["set_archived"] || o.something[0].archived).length > 0;
or
_.some(content, o => o["set_archived"] || o.something[0].archived);
PlainJs:
content.some(o => o["set_archived"] || o.something[0].archived)
or
content.filter(o => o["set_archived"] || o.something[0].archived).length > 0;

You can just use some() in plain javascript.
var content = [{
"set_archived": false,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2016-12-01T18:23:29.743333Z",
"created": "2016-12-01T18:23:29.743333Z",
"archived": false
}]
}, {
"set_archived": true,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2017-01-30T19:42:29.743333Z",
"created": "2017-01-30T19:42:29.743333Z",
"archived": false
}]
}];
var result = content.some(function(e) {
return e.set_archived === true || e.something[0].archived === true
})
console.log(result)

Considering the same object as the one in the question, there are couple of ways to find the solution to your problem mate.
var flag = false;
flag = content.some(function(c){
if(c["set_archived"]){
return true;
}
});
console.log(flag)
or
var flag = false;
flag = content.some(function(c){
if(c["set_archived"] || c.something[0].archived){
return true;
}
});
console.log(flag)
The above snippet will result true if atleast one of the object of the array have ["set_archived"] property true and it will return false if all the objects of the array has ["set_archived"] as false. (I could have said vice-versa)
The some() method tests whether some element in the array passes the test implemented by the provided function.
The every() method tests whether all elements in the array pass the test implemented by the provided function.
If you are looking for a stricter way I recon you go ahead with every().

You don't need lodash for this. You can do this with pure JS, using filter:
content.filter(i => i.set_archived || i.something.archied)

Related

javascript array is coming as empty

I need to return whole object where linkable is true. I think I am doing it in a right way but array is coming as empty. this.releaseDescriptionDatesArray is empty even I am pushing the object.
for (const item of this.datesArray) {
for (const attribute in item) {
if (attribute === 'linkable' && item[attribute] === 'true') {
this.releaseDescriptionDatesArray.push(item); // data is here
console.log( this.releaseDescriptionDatesArray, "datesArr");data is not coming here
}
}
}
console.log( this.releaseDescriptionDatesArray, "datesArr"); data is not here
}
Sample data
datesArray = [ {
"type": "disasterRecovery",
"date": "2019-07-28",
"releaseWindow": {
"start": null,
"end": null
},
"description": "Disaster Recovery",
"linkable": true
},
{
"type": "nooutageRelease",
"date": "2019-08-03",
"releaseWindow": {
"start": "2019-08-04T00:00:00",
"end": "2019-08-04T23:59:59"
},
"description": "Infrastructure Release (No Outage)",
"linkable": true
}]
If you know there is going to be an attribute linkable in every item, you don't need to parse every attribute of the items and check if one of them is linkable then check if it's true.
Also, since your are stritcly comparing your values (===), 'true' !== true, that's probably why your array is empty. With that in mind, you could simply use the filter function on your array with a callback that check if linkable is true. It will simplify a lot your code.
let datesArray = [{
"type": "disasterRecovery",
"date": "2019-07-28",
"releaseWindow": {
"start": null,
"end": null
},
"description": "Disaster Recovery",
"linkable": true
},
// i've change the value of this item for testing purpose
{
"type": "nooutageRelease",
"date": "2019-08-03",
"releaseWindow": {
"start": "2019-08-04T00:00:00",
"end": "2019-08-04T23:59:59"
},
"description": "Infrastructure Release (No Outage)",
"linkable": false
}
];
// this callback will assert that date.linkable is not null,
// and that it's value is true.
// if the attribute was null ( or undefined ), it would be evaluated as "false-y" and therefore
// not be included in the final array.
// the last part also check that the value is an actual boolean ( see Lain's comment )
let output = datesArray.filter((date) => date.linkable && date.linkable === true);
console.log(output)
item[attribute] === true
You need to use boolean true, not string 'true'
for (var item of datesArray) {
for (var attribute in item) {
if (attribute === 'linkable' && item[attribute] === true) {
releaseDescriptionDatesArray.push(item); // data is here
console.log(attribute)
console.log(this.releaseDescriptionDatesArray, "datesArr");
}
}
}

How to save initial statement of object?

I have object of type:
export interface IGroupLanguage {
name: string;
languages?: Language[];
}
let data = [ { "name": "Automation", "languages": [ { "Name": "English", "Lcid": 1, "RightToLeft": true, "Code": "EN", "Mapped": true } ] }, { "name": "Monitors", "languages": [ { "Name": "Russian", "Lcid": 2, "RightToLeft": true, "Code": "RU", "Mapped": true } ] } ];
Then I tried to filter object and return a new object:
this.filteredObject = [...this.groups];
this.filteredObject.map(item => {
item.languages = item.languages.filter(
lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery) != -1
);
});
Problem is that initial object this.groups is changed also. How to save initial statement of object?
In result I need to have not modified object this.groups and filtered object this.filteredObject.
I know problem because JS copy objects by reference, but I dont know how to solve it.
Full code is:
search(searchQuery: string) {
this.filteredObject = [...this.groups];
this.filteredObject.map(item => {
let tempLang = [...item.languages];
item.languages = tempLang.filter(
lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery) != -1
);
});
console.log(this.groups);
}
ngOnInit() {
this.filteredObject = [...this.groups];
}
As result initial object console.log(this.groups); is also was modified
Because you have deep copied parent array of data not nested one, can you give it a try to below way -
this.filteredObject = [...this.groups];
this.filteredObject.map(item => {
let tempLang = [...item.languages];
item.languages = tempLang.filter(lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery) != -1
);
});
Spread syntax performs a shallow copy of the object.
MDN documentation on copying an array with spread syntax:
Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays as the following example shows (it's the same with Object.assign() and spread syntax).
This means that if there are any objects at the top level, their reference will be copied. That is the reason for this problem.
You can use JSON.parse(JSON.stringify()) to deep clone an object. But there will be data loss if the object has Dates, functions, undefined, Infinity, or other complex types. More info in this answer.
Also, when you are not returning any values use forEach() instead of a map().
this.filteredObject = JSON.parse(JSON.stringify(this.groups));
filteredObject.forEach(item => {
item.languages = item.languages.filter(lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1
);
});
This works for properties containing objects at any nested level.
Live Example:
let data = [ { "name": "Automation", "languages": [ { "Name": "English", "Lcid": 1, "RightToLeft": true, "Code": "EN", "Mapped": true } ] }, { "name": "Monitors", "languages": [ { "Name": "Russian", "Lcid": 2, "RightToLeft": true, "Code": "RU", "Mapped": true } ] } ];
let searchQuery = "English";
let filteredObject = JSON.parse(JSON.stringify(data));
filteredObject.forEach(item => {
item.languages = item.languages.filter(lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1
);
});
console.log(data);
console.log(filteredObject);
You need to deep clone your object. If you know the structure of your object, you can create a custom deep clone function with recursiveness. Otherwise, you can use the library lodash

How to check if multiple objects in array have the same property value?

Hey guys I want to know what is the best approach to check wether two or more objects has the same property value in my case dueTo?
My array looks like this
Array [
Object
"__typename": "Instalment",
"_id": "5cd022cf0d805222374197eb",
"description": "Description",
"dueTo": "2019-05-16T23:00:00.000Z",
"instalmentAmount": 200000,
"paid": false,
},
Object {
"__typename": "Instalment",
"_id": "5cd022cf0d805222374197ea",
"description": "Description",
"dueTo": "2019-05-23T23:00:00.000Z",
"instalmentAmount": 200000,
"paid": false,
},
Object {
"__typename": "Instalment",
"_id": "5cd022cf0d805222374197e9",
"description": "Description",
"dueTo": "2019-05-23T23:00:00.000Z",
"instalmentAmount": 200000,
"paid": false,
},
]
First I want to know which objects include the value paid: false
const unpaidInstalments = instalments.filter(
instalment => !instalment.paid
);
Now I want to check if there are instalments in the same day in this case will result to index 1 and 2 and here the question come how do I filter this?
SOLVED
Get all the available dates and put them in an object then check if there is more than 1 object which contain the same value and return an array with these objects
const sameDayArray = unpaidInstalments.reduce(
(datesToCheck, instalment) => {
datesToCheck[instalment.dueTo] =
(datesToCheck[instalment.dueTo] || 0) + 1;
return datesToCheck;
},
{}
);
const instalmentsSameDay = unpaidInstalments.filter(instalment => {
return sameDayArray[instalment.dueTo] > 1;
});

Matching certain value in JSON Array using match() or find() in JavaScript

I'm looking for a function or method to overcome this issue
Here is the JSON Array
[{
"type": "radar",
"detail": [{
"subject": "sub1"
}, {
"subject": "sub2"
}]
}, {
"type": "bar",
"detail": [{
"subject": "sub1"
}, {
"subject": "sub2"
}]
}]
I'm hoping to identify the value of "type" which in this case would be "radar" and "bar",and match with the variable x。
Here's the code:
for(x in myarray)
{
if(myarray[x]['type']=="bar")
{
console.log("equal");
}
else
{
console.log("no result");
}
}
With this code,the result on the website console would be both "equal" and "no result",while I wish to print "equal" only.I understand the logic error in this code,but I couldn't figure out the correct way to fix it.
You can use Array.some for this which return true or false if one of the array element match with type "bar" then It will return true otherwise false
var data = [{
"type": "radar",
"detail": [{
"subject": "sub1"
}, {
"subject": "sub2"
}]
}, {
"type": "bar",
"detail": [{
"subject": "sub1"
}, {
"subject": "sub2"
}]
}]
if (data.some(val => val.type == "bar"))
console.log("Equal")
else
console.log("No record found");
let myArr = [
{ "type":"radar",
"detail": [
{ "subject":"sub1" },
{ "subject":"sub2" }
]
},
{ "type":"bar",
"detail": [
{ "subject":"sub1" },
{ "subject":"sub2" }
]
}
]
for(let x of myArr){
if(x.type === 'bar'){ console.log('equal')}
else { console.log('no result')}
}
In order to understand what went wrong with your code, first when you have a for loop, you need to have a let/var keyword as below:
for(let x of myArr)
Secondly, instead of using for..in loop, which it meant for looping property of objects, use for..of loop which meant for looping array.
Third, while looping myArr, each and every element x is an object and type is the property, so just use x.type to make the comparison.
Lastly, as others have mentioned, Array#some / Array#find is a better way to deal with finding existence of element in an array
Since the for loop runs for each object in the array, the first console log for equal is for matched type and second console log is for the unmatched type. So, to get only one console and to write more appropriate code, you can use Array.find() and then add a if-else block for that. Something like this:
var myarray = [ { "type":"radar", "detail": [{ "subject":"sub1" }, { "subject":"sub2" }] }, { "type":"bar", "detail": [{ "subject":"sub1" }, { "subject":"sub2" }] } ];
var match = myarray.find(({type}) => type === "bar");
if(match) {
console.log("equal");
} else {
console.log("no result");
}

Getting JSON object values by name

I have a valid JSON object like this:
{
"reasons": {
"options": [
{
"value": "",
"label": "Choose a reason",
"selected": true,
"requiresValidation": false
},
{
"value": "small",
"label": "Too little",
"selected": false,
"requiresValidation": false
},
{
"value": "big",
"label": "Too big",
"selected": false,
"requiresValidation": false
},
{
"value": "unsuitable",
"label": "I don't like it",
"selected": false,
"requiresValidation": true
},
{
"value": "other",
"label": "Other",
"selected": false,
"requiresValidation": true
}
]
}
}
and I have a variable which stores one value (e.g. unsuitable) of an option available in options.
How can I retrieve the value of requiresValidation field for the value stored in the variable without having to loop through all of the objects values inside options?
For instance, if the var content is other I'd like to access to requireValidation field of the object whose value is other (which is true). Is it possible?
Thank you.
You aren't really dealing with JSON here, you are dealing with a JS object. JSON is just a format for sending JS objects.
options is an array. The only way to access it is by index, which means you will have to do a search, one item at a time. There are functions, such as indexOf() which will return the first index of a value in an array, however, you have an array of objects, so that will not work in this case. (And internally, it is still doing a search).
function getReqVal(val) {
for (var item in mydata.reasons.options) {
if(item.value == val) {
return item.requiresValidation;
}
}
}
getReqVal("other");
The caveat is that this will return on the first one, so if you have more than one other, you won't get them.
If the options are indeed unique values, I would rearrange your object to be an associative array, with the keys being the "value" items, and the values being an object with the rest of the data:
{
"reasons": {
"options": {
"" : {
"label": "Seleziona una voce",
"selected": true,
"requiresValidation": false
},
"small" : {
"label": "Too little",
"selected": false,
"requiresValidation": false
},
"big" : {
"label": "Too big",
"selected": false,
"requiresValidation": false
},
"unsuitable" : {
"label": "I don't like it",
"selected": false,
"requiresValidation": true
},
"other" : {
"label": "Other",
"selected": false,
"requiresValidation": true
}
}
}
}
If you are (or could be) using underscore.js you could use the find method:
var item = _.find(myObj.reasons.options,
function(option){ return option.value == 'some value' });
Assuming you can't change the JSON structure itself (because perhaps you're getting it from an external source?), you can read it into a new object of your design per Marc B's suggestion. Ideally, this new object would let you index into your options array using the value key. Let's do that:
function MyOptions(optionsJSON) {
this.original_json = optionsJSON;
this.length = optionsJSON.reasons.options.length;
var original_options = optionsJSON.reasons.options;
for(var i = 0; i < this.length; i++)
this[original_options[i].value] = original_options[i];
}
var my_opts = new MyOptions(original_JSON);
var item_requiresValidation = my_opts["unsuitable"].requiresValidation;
console.log(item_requiresValidation); // should log "true"
The trade-off here is that your code will need to loop through the entire options array once, but after that you can index into the objects using the value key without searching. Validate with this jsfiddle.
You could use array filter. Some variation of this:
var $reasons = //Your JSON
function checkVal(element, index, array) {
return (element.value == "other");
}
var filtered = $reasons.reasons.options.filter(checkVal);
alert(filtered[0].requiresValidation);
Or jQuery grep might help you with the filter without looping: http://api.jquery.com/jQuery.grep/

Categories