Check if there are null values in an array of objects - javascript

I have this array of objects.
[Object, Object, Object]
0:Object
name: "Rick"
Contact: "Yes"
Date:'null'
Location:'null'
1:Object
name:"Anjie"
Contact:"No"
Date:'13/6/2016'
Location:'LA'
2:Object
name:"dillan"
Contact:"Maybe"
Date:'17/6/2016'
Location:'NY'
As you can see, there are null values for Object[0] for Date and Location. I want to check if there is a null value present in the entire array of Objects.
If there is a null value present for 'Date' and 'Location', i should be able to display 'Null present' at the console. If no null values are present, it should display 'Data right' at the console.
can someone please let me know how to achieve this.

var wasNull = false;
for(var i in objectsArray) {
if(objectsArray[i].Date == null || objectsArray[i].Location == null) wasNull = true;
}
if(wasNull) console.log('Was null');
else console.log('Data right');

Do it using Object.keys() and Array#some methods
var data = [{
name: "Rick",
Contact: "Yes",
Date: null,
Location: null
}, {
name: "Anjie",
Contact: "No",
Date: '13/6/2016',
Location: 'LA'
}, {
name: "dillan",
Contact: "Maybe",
Date: '17/6/2016',
Location: 'NY'
}];
// iterate over array elements
data.forEach(function(v, i) {
if (
// get all properties and check any of it's value is null
Object.keys(v).some(function(k) {
return v[k] == null;
})
)
console.log('null value present', i);
else
console.log('data right', i);
});

Use some() and check if there is a null.
var arr = [
{ a : "a", b : "b", c : "c" },
{ a : "a", b : "b", c : "c" },
{ a : "a", b : "b", c : null }
];
function hasNull(element, index, array) {
return element.a===null || element.b===null || element.c===null;
}
console.log( arr.some(hasNull) );
If you do not want to hardCode the if, than you need to add another loop and loop over the keys.
var arr = [
{ a : "a1", b : "b1", c : "c1" },
{ a : "a2", b : "b2", c : "c2" },
{ a : "a3", b : "b3", c : null }
];
function hasNull(element, index, array) {
return Object.keys(element).some(
function (key) {
return element[key]===null;
}
);
}
console.log( arr.some(hasNull) );
or JSON with a reg exp (
var arr = [
{ a : "a1", b : "b1", c : "c1" },
{ a : "a2", b : "b2", c : "c2" },
{ a : "a3", b : "b3", c : null }
];
var hasMatch = JSON.stringify(arr).match(/:null[\},]/)!==null;
console.log(hasMatch);

A solution using underscore:
var nullPresent = _.some(data, item => _.some(_.pick(item, 'Date', 'Location'), _.isNull));

Related

If object set has an object property create an array

I have a response value which is dynamic which i need to store in redux state,
Response consist of array of object and and name
ex :
{data:[
{name:"abc",age:"10",id:"10"}
{name:"abc",age:"15",id:"20"}
{name:"def",age:"15",id:"20"}
]
name: "abc"
}
So if the name is same I need to create array with the name.
Expected :
abc:[
{name:"abc",age:"10",id:"10"}
{name:"abc",age:"15",id:"20"}
]
something I tried
data.map(function(o) {
if(data.name ==o.name)
return name[o];
});
If you're wanting a new object with a key of the name property you could try something like this
const response = {
data: [{
name: "abc",
age: "10",
id: "10"
},
{
name: "abc",
age: "15",
id: "20"
},
{
name: "def",
age: "15",
id: "20"
},
],
name: "abc"
}
const createSet = (someData) => {
let key = someData.name
let data = someData.data.filter(e => e.name === key)
return {
[key]: data
}
}
console.log(createSet(response))
You can extract duplicated using reduce and filter :
var data = {
data:[
{name:"abc",age:"10",id:"10"},
{name:"abc",age:"15",id:"20"},
{name:"def",age:"15",id:"20"}
],
name: "abc"
}
const lookup = data.data.reduce((a, e) => {
a[e.name] = ++a[e.name] || 0;
return a;
}, {});
console.log(data.data.filter(e => lookup[e.name]));

Return string from an attribute in array of objects

I m working on nested array of objects, where I require return to be a
specific string from an object which satisfies below conditions as
shown in the code. But as we know forEach returns undefined, and my
requirement is a single string as return, can any new es6 in built
array functions be used to make it more easy? in below code value in second loop is received
from a function, so ignore its source
const data = [
{
column:"a" ,
children:[
{column: "a1", area: { defaultValue:"NY", selectedValue: "NJ"} },
{column: "a2", area: { defaultValue:"IN", selectedValue: "CA"} },
]
},
{
column:"b" ,
children:[
{column: "b1", area: { defaultValue:"JP", selectedValue: "CC"} },
{column: "b2", area: { defaultValue:"CA", selectedValue: "BL"} },
]
},
];
const newValue = data.forEach( d => {
if (d.column === "a" && children) {
children.forEach(c => {
if (c.column === value) {
return c.area.selectedValue || c.area.defaultValue;
}
})
}
})
console.log(newValue);
This may be one possible way to obtain the desired objective:
const getNewValue = (val1 = 'a', val2 = 'a2') => {
const foundIt = data?.find(
d => d.column === val1
)?.children?.find(
c => c.column === val2
);
return foundIt?.area?.selectedValue ||
foundIt?.area?.defaultValue ||
'No matching entry found';
}
Explanation
Use find to get a match on the column.
Use ?. optional-chaining to refer children within the matched object
.find the matching value (such as a1, or a2, etc) within children
return either the selectedValue or defaultValue or, if both are falsy, a string-constant to notify no matches.
Code Snippet
const data = [
{
column:"a" ,
children:[
{column: "a1", area: { defaultValue:"NY", selectedValue: "NJ"} },
{column: "a2", area: { defaultValue:"IN", selectedValue: "CA"} },
]
},
{
column:"b" ,
children:[
{column: "b1", area: { defaultValue:"JP", selectedValue: "CC"} },
{column: "b2", area: { defaultValue:"CA", selectedValue: "BL"} },
]
},
];
const getNewValue = (val1 = 'a', val2 = 'a2') => {
const foundIt = data?.find(
d => d.column === val1
)?.children?.find(
c => c.column === val2
);
return foundIt?.area?.selectedValue ||
foundIt?.area?.defaultValue ||
'No matching entry found';
}
console.log(getNewValue());
console.log(getNewValue('a', 'a1'));
console.log(getNewValue('b', 'b1'));
console.log(getNewValue('b'));
Array.prototype.find() should do the trick!
var value = "a1"
data.forEach(e => {
if (e.column === "a")
foundValue = e.children.find(c =>
c.column === value
)
})
wantedValue = foundValue.area.selectedValue || foundValue.area.defaultValue
console.log(wantedValue)

Methods to insert or replace values in to object

I've got an object like this
var obj2= {
'home' : {
'1' : {
'year' : '1999'
},
'2' : {
'year' : '2000'
'month' : '11'
},
},
'company' : {
'1' : {
'year' : '2010'
'month' : '2'
},
}
};
And I would like to add some more keys inside the object or replace value if this key chain already exists, for ex:
buss_type = "home",
type_id = "1",
date_type = "month",
value = "9"
var tmp_obj1 = {[buss_type]: {[type_id]: {[date_type]: value}}};
and
buss_type = "company",
type_id = "2",
date_type = "month",
value = "12"
var tmp_obj2 = {[buss_type]: {[type_id]: {[date_type]: value}}};
to make object:
obj = {
'home' : {
'1' : {
'year' : '1999',
'month' : '9'
},
'2' : {
'year' : '2000',
'month' : '11'
},
},
'company' : {
'1' : {
'year' : '2020',
'month' : '10'
},
'2' : {
'month' : '12'
}
},
};
Arrays methods like .push() or .concat() adding new keys on the end only instead of replacing values of existing ones.
Are there any object methods that can make it easy to manage or should I just use loops and check all keys before adding new or changing value of existing one?
Thanks.
You could take an array for the keys and save the last key for direct assignment.
function setValue(object, path, value) {
var last = path.pop();
path.reduce(function (o, k) {
return o[k] = o[k] || {};
}, object)[last] = value;
}
var object = { home: { 1: { year: '1999' }, 2: { year: '2000', month: '11' } }, company: { 1: { year: '2010', month: '2' } } };
setValue(object, ["home", "1", "month"], "9");
setValue(object, ["company", "2", "month"], "12");
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use reduce() method to add nested properties to object.
var obj2 = {"home":{"1":{"year":"1999"},"2":{"year":"2000","month":"11"}},"company":{"1":{"year":"2010","month":"2"}}}
function add(obj, value, ...keys) {
keys.reduce(function(r, e, i, arr) {
return r[e] || (r[e] = arr[i + 1] ? {} : value)
}, obj)
}
let buss_type = "home", type_id = "1", date_type = "month", value = "9";
add(obj2, value, buss_type, type_id, date_type)
buss_type = "company", type_id = "2", date_type = "month", value = "12"
add(obj2, value, buss_type, type_id, date_type)
console.log(obj2)
If you will only have objects without any methods inside, just simple JSON style objects. Then you can use something like
JSON.stringify(obj1) === JSON.stringify(obj2)
Just be careful that the order of the object data is important. For example, this will return false
x = {a: 1, b: 2};
y = {b: 2, a: 1};
You don't need to create a loop instead you can programmatically access the key you're about to add using this syntax:
buss_type = "home",
type_id = "1",
date_type = "month",
value = "9"
if(obj[buss_type]){
if(obj[buss_type][type_id]){
obj[buss_type][type_id][date_type] = value
}else{
obj[buss_type][type_id] = { date_type: value }
}
}else{
obj[buss_type] = { type_id: { date_type: value } }
}

Lodash. Smart merge two objects by keys

I have the two objects. A and B.
A
{
"beta" : {
"value": null,
"error" : null
},
"hamma" : {
"value": null,
"error" : null
},
"zerta" : {
"value": null,
"error" : null
},
"mozes" : 5
}
B
{
"beta" : 5,
"hamma" : 2
}
How do I can loop through the A keys, compare it with the B object and update the values of the existing keys in the A object via Lodash? Maybe there is exists some nice way? I tried to use "assing, assignWith" but looks like I haven't understood how it works.
The result should looks like that:
{
"beta" : {
"value": 5,
"error" : null
},
"hamma" : {
"value": 2,
"error" : null
},
"zerta" : {
"value": null,
"error" : null
},
"mozes" : 5
}
Thanks for any information.
I have resolved this solution via native js by that way but I want to know how can I do it via Lodash.
export function mapServerModelToStateValues(state, serverModel) {
let updatedState = {};
const serverModelKeyList = Object.keys(serverModel);
Object.keys(state).forEach(stateKey => {
serverModelKeyList.forEach(modelKey => {
if ( modelKey === stateKey ) {
updatedState[ stateKey ] = {
...state[ stateKey ],
value : serverModel[ modelKey ]
}
}
});
});
console.log(updatedState);
}
You can use _.mergeWith lodash method and pass custom function.
var a = {"beta":{"value":null,"error":null},"hamma":{"value":null,"error":null},"zerta":{"value":null,"error":null},"mozes":5}
var b = {"beta":5,"hamma":2, "mozes": 123}
_.mergeWith(a, b, function(aValue, bValue) {
_.isPlainObject(aValue) ? aValue.value = bValue : aValue = bValue
return aValue
})
console.log(a)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Here's a solution that iterates over the B array and uses set to update the value:
_.each(updates, (value, key) => _.set(data, `${key}.value`, value))
This will do the trick, notice that the result will have all the keys in the same value, error format
const A = {
"beta": {
"value": null,
"error": null
},
"hamma": {
"value": null,
"error": null
},
"zerta": {
"value": null,
"error": null
},
"mozes": 5
}
const B = {
"beta": 5,
"hamma": 2
}
const C = _.mapValues(A, (value, key) => {
return {
...value,
value: B[key] || value.value
}
});
console.log(C)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Map through the _keys from your second object to update the first object accordingly:
// obj a
const a = {
beta: {
value: null,
error: null
},
hamma: {
value: null,
error: null
},
zerta: {
value: null,
error: null
},
mozes: 5
};
// obj b
const b = {
beta: 5,
hamma: 2
};
// map through the 'obj b' keys and update 'obj a' accordingly
_.keys(b).map(key => {
a[key].value = b[key];
});
// log obj a to the console
console.log(a);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Update: I would use the solution from #GruffBunny - the idea is similar to this one, but done much more elegantly using lodash.
You can use lodash#merge and lodash#mapValues to achieve this.
var result = _.merge({}, a, _.mapValues(b, value => ({ value })));
var a = {
"beta" : {
"value": null,
"error" : null
},
"hamma" : {
"value": null,
"error" : null
},
"zerta" : {
"value": null,
"error" : null
},
"mozes" : 5
};
var b = {
"beta" : 5,
"hamma" : 2
};
var result = _.merge({}, a, _.mapValues(b, value => ({ value })));
console.log(result);
.as-console-wrapper { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Javascript multiple condition array filter

I need help putting together an array search that is based on multiple conditions. Furthermore, all the conditions are conditional, meaning I may or may not need to filter on those conditions. What I have:
Array of objects to filter:
var data = [{
"_id" : ObjectId("583f6e6d14c8042dd7c979e6"),
"transid" : 1,
"acct" : "acct1",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category1",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 2,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category2",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 3,
"acct" : "acct2",
"transdate" : ISODate("2016-07-31T05:00:00.000Z"),
"category" : "category1",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 4,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category2",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 5,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category3",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c152g2"),
"transid" : 6,
"acct" : "acct3",
"transdate" : ISODate("2016-10-31T05:00:00.000Z"),
"category" : "category3",
"amount" : 103
}]
I am filtering the above array of objects based on another array of mixed elements. The elements represent the following search fields:
"searchstring": to search on all fields in the data array for any
matched text sequence
object with key values reprsenting account type and a true or false
for value indicating if it should be used to filter
startdate to filter transdate on
enddate to filter transdate
category name to filter category on
The array that has the search conditions looks like this (but if some of the fields are not necessary they will be set to undefined or just an empty string or array):
var filtercondition = {
"p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
}
What is the best way to accomplish this? What I've devised is a separate search for each element in the filter array, but this seems non optimal and very tedious. I'm open to a redesign of my setup...
// You wrote that it's an array, so changed the braces
var filtercondition = ["p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
];
var filtered = data.filter(o => {
if(filtercondition[0] && !o.category.includes(filtercondition[o])) { // checking just the category, but you can check if any of more fields contains the conditions
return false;
}
if(filtercondition[1]) {
for(var key in filtercondition[1]) {
if(filtercondition[1][key] === true && o.acct != key) {
return false;
}
}
}
if(filtercondition[2] && o.transdate < filtercondition[2]) {
return false;
}
if(filtercondition[3] && o.transdate > filtercondition[3]) {
return false;
}
if(filtercondition[4] && o.category !== filtercondition[4]) {
return false;
}
return true;
});
Two notes:
- changed the braces of filtercondition so that it is an array, however I would suggest to use an object instead.
- this {acct1:true,acct2:false,acct3:true...} sample doesn't make sense for me, since it suggests that the acct field should be acct1 and acct3 at the same time.
Create an array of functions, each function representing a condition.
Here's some sample code which demonstrates the approach...
var conditions = [];
// Dynamically build the list of conditions
if(startDateFilter) {
conditions.push(function(item) {
return item.transdate >= startDateFilter.startDate;
});
};
if(categoryFilter) {
conditions.push(function(item) {
return item.cateogry === categoryFilter.category;
});
};
// etc etc
Once you have an array of conditions, you can use Array.prototype.every to run each condition on an item.
var itemsMatchingCondition = data.filter(function(d) {
return conditions.every(function(c) {
return c(d);
});
});
Or, using the more compact arrow functions:
const itemsMatchingCondition = data.filter(d => conditions.every(c => c(d));
First, you'll want to use brackets for your array not curly braces:
var filtercondition = [
"p",
{acct1:true,acct2:false,acct3:true...},
"2016-06-01",
"2016-11-30",
"category3"
];
Then again, I don't think that an array is the best data type for that. Try an object like this:
var filtercondition = {
query: "p",
accounts: {acct1:true,acct2:false,acct3:true...},
date1: "2016-06-01",
date2: "2016-11-30",
category: "category3"
};
Then, try using Array.prototype.filter:
var filtered = data.filter(function(obj) {
for (var key in filtercondition) {
// if condition not met return false
}
return true;
});
I'd go with a bunch of small granular functions and compose them.
//only some utilities, from the top of my mind
var identity = v => v;
//string-related
var string = v => v == null? "": String(v);
var startsWith = needle => haystack => string(haystack).startsWith(needle);
var endsWith = needle => haystack => string(haystack).endsWith(needle);
var contains = needle => haystack => string(haystack).contains(needle);
//do sth with an object
var prop = key => obj => obj != null && prop in obj? obj[prop]: undefined;
var someProp = fn => obj => obj != null && Object.keys(obj).some(k => fn(k) );
var someValue = fn => obj => obj != null && Object.keys(obj).some(k => fn(obj[k]) );
//logic
var eq = b => a => a === b;
var not = fn => function(){ return !fn.apply(this, arguments) };
var and = (...funcs) => funcs.reduce((a, b) => function(){
return a.apply(this, arguments) && b.apply(this, arguments);
});
var or = (...funcs) => funcs.reduce((a, b) => function(){
return a.apply(this, arguments) || b.apply(this, arguments);
});
//composition
var compose = (...funcs) => funcs.reduce((a, b) => v => return a(b(v)));
var chain = (...funcs) => funcs.reduceRight((a, b) => v => return a(b(v)));
//and whatever else you want/need
//but stay granular, don't put too much logic into a single function
and an example composition:
var filterFn = and(
//some value contains "p"
someValue(contains("p")),
//and
chain(
//property "foo"
prop("foo"),
or(
//either contains "asdf"
contains("asdf"),
//or startsWith "123"
startsWith("123")
)
),
)
since I don't know how you build your filterconditions, I cannot tell you exactly how to parse them into such a composition, but you could compose them like this:
//start with something basic, so we don't ever have to check wether filterFn is null
var filterFn = identity;
//and extend/compose it depending on some conditions
if(/*hasQuery*/){
filterFn = and(
// previous filterFn(obj) && some value on obj contains `query`
filterFn,
someValue(contains(query)))
)
}
if(/*condition*/){
//extend filterFn
filterFn = or(
// (obj.foo === null) || previous filterFn(obj)
chain(prop("foo"), eq(null)),
filterFn
);
}
and so on
First, some points:
Your data object is invalid if you're going to use it in the browser. Probably the data comes from MongoDB, right? Your backend (data source) should have a method to encode it properly and remove ObjectID and ISODate references.
Your filtercondition is not a valid JavaScript object/JSON. Check my example.
So, you can filter your data array with Array#filter method.
Something like that:
let data = [{
"_id" : "583f6e6d14c8042dd7c979e6",
"transid" : 1,
"acct" : "acct1",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category1",
"amount" : 103
},
{
"_id" : "583f6e6d14c8042dd7c2132t6",
"transid" : 2,
"acct" : "acct2",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category2",
"amount" : 103
},
{
"_id" : "583f6e6d14c8042dd7c2132t6",
"transid" : 5,
"acct" : "acct2",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category3",
"amount" : 103
}];
let filterToApply = {
acct: {
acct1: true,
acct2: false,
acct3: true
},
initialDate: "2016-06-01",
finalDate: "2016-11-30",
category: "category3"
}
let filterData = (array, filter) => {
return array.filter( (item) => {
/* here, you iterate each item and compare with your filter,
if the item pass, you must return true. Otherwise, false */
/* e.g.: category check (if present only) */
if (filter.category && filter.category !== item.category)
return false;
}
/* add other criterias check... */
return true;
});
}
let dataFiltered = filterData(data, filterToApply);
console.log(dataFiltered);
If you want to filter an array with multiple conditions and the conditions may be optional, then use the following method.
const data = [
{ name: 'John', age: 25, city: 'New York' },
{ name: 'John', age: 25, city: 'New' },
{ name: 'Jane', age: 32, city: 'Los Angeles' },
{ name: 'Bob', age: 45, city: 'New York' },
{ name: 'Alice', age: 38, city: 'Los Angeles' }
];
const filteredData = (n, c, a) => data.filter(item => {
if (n || c || a) {
return (n ? item.name === n : true) && (c ? item.city === c : true) && (a ? item.age === a : true); // keep adding conditons as much as u want
}
});
console.log(filteredData('John', null, 25));
console.log(filteredData(null, 'Los Angeles', 38));
console.log(filteredData(null, 'Los Angeles', null));
You can chain as many as conditions

Categories

Resources