Trying to filter an array of objects based on an object returned by user, returning a new array. I've tried everything I could. Can't get what others have posted to work either because I need to check every object value to be either matching or undefined in the user object (undefined means user has no preference, lets say). Here is what I have come up with, three functions. None of these functions work. Even one working solution is great, but if someone has time to explain why the rest don't work that would be a bonus. This should return the Ford Mustang object. Also have to figure out how to specify a range of numbers, for the zeroSixty. I'm a beginner, having issues with syntax.
const carArray = [
{
brand: 'Mazda',
model: '3',
trim: 'base',
year: 2022,
drive: ['FWD', 'AWD'],
LKA: true,
laneCenter: false,
handsFree: false,
style: 'sedan',
zeroSixty: 7.5
},
{
brand: 'Ford',
model: 'Mustang Mach E',
trim: 'base',
year: 2022,
drive: ['FWD', 'AWD'],
LKA: true,
laneCenter: true,
handsFree: true,
style: 'SUV',
zeroSixty: 3.7
},
{
brand: 'KIA',
model: 'Forte',
trim: 'GT',
year: 2022,
drive: ['FWD'],
LKA: true,
laneCenter: true,
handsFree: false,
style: 'sedan',
zeroSixty: 6.4
},
]
const userCar =
{
brand: undefined,
model: undefined,
trim: undefined,
year: 2022,
drive: undefined,
LKA: true,
laneCenter: true,
handsFree: undefined,
style: 'SUV',
zeroSixty: undefined
};
const result = carArray.filter(x => userCar.some(y => (x.Object.values(carArray) === y.Object.values(userCar)) || (y.Object.values(userCar) === undefined)));
console.log(result);
const condensedCarFilter = (userCar, carArray) => {
return carArray.filter(obj => {
return obj.values.every(feature => {
return ((userCar.values.includes(feature) === true) || (userCar.values.includes(feature) === undefined));
})
})
};
let contensedTest = condensedCarFilter(userCar, carArray);
console.log(condensedTest);
const findCar = (userCar, carArray) => {
filteredArray = [];
for (x =0; x < carArray.length; x++) {
if ((Object.values(carArray[x]) === Object.values(userCar)) || (Object.values(userCar) === undefined)) {
filteredArray.push(carArray[x])
console.log(Object.values(carArray[x]));
}
}
console.log(filteredArray);
};
findCar(userCar, carArray);
I've created a jsfiddle you can look at here: https://jsfiddle.net/rlouie/6osq9kgn/1/
With the criteria you specified, this works:
function filterToDefinedAndMatching(car) {
return Object.entries(car).every(([key, value]) => !userCar[key] || userCar[key] == value);
}
const matchingCars = carArray.filter(filterToDefinedAndMatching);
However, you will run into problems once you want to match on drive, since it is an array. Array equality is by reference not value, and it won't match, so you need even more:
function betterFilterToMatchCars(car) {
return Object.entries(car).every(([key, value]) => {
const userCarValue = userCar[key];
if (Array.isArray(userCarValue)) {
return userCarValue.every(item => value.includes(item));
} else {
return !userCarValue || userCarValue == value;
}
});
}
If your car object keeps getting more complex, you really just need a more generic deep equals check, which you can find more about here:
Object comparison in JavaScript
Related
My goal here is to convert all type values in the array below to the types in the object that collerate to numbers.
let obj = [
{
type: 'boolean',
name: 'coolName',
description: 'First description',
required: false
},
{
type: 'subcommand',
name: 'destroy',
description: 'Destroy something',
options: [
{
type:"integer",
name:"amount",
description:"How much would you like to destroy?",
required: true
}
]
}
]
const types = {
'subcommand':1,
'subcommandgroup':2,
'string':3,
'integer':4,
'boolean':5,
'user':6,
'channel':7,
'role':8,
'mentionable':9,
'number':10,
'attachment':11
}
I've been looking for a while and cannot find a function that also iterates through the nested object, if anyone has a way to do this please let me know.
obj.map(o => {
o.type = types[o.type]
if(o.options){
o.options.map(opt => {
opt.type = types[opt.type]
})
}
return o;
})
I am currently working with objects and arrays in nodejs in conjuction with filters. I am currenlty facing difficulty in figuring out how to properly traverse an object and filter for the desired results. Instead I am getting undefined. I have an object users and I am wanting to filter for each user configuration that has active === true and then ultimately display every users configuration with that filter in the final result. What is the right/best way to approach this? Should I use map?
Current Result:
undefined
Desired Result:
[
{
email: 'test1#email.com',
active: true
},
{
email: 'test3#email.com',
active: true
},
{
email: 'test4#email.com',
active: true
}
]
Code:
const users = [
{
name: 'User1',
configuration: [
{
email: 'test1#email.com',
active: true
},
{
email: 'test2#email.com',
active: false
}
],
},
{
name: 'User2',
configuration: [
{
email: 'test3#email.com',
active: true
},
{
email: 'test4#email.com',
active: true
}
],
},
];
const result = users.forEach(user => user.configuration.filter( x => {
let {
active
} = x;
return active === true;
}));
console.log(result);
you can use flatMap for this. forEach always returns undefined. usually if you want to return some array use map but since filter also returns an array you need to flat it to get your desired result hence flatMap
const users = [{name: 'User1',configuration: [ {email: 'test1#email.com',active: true},{email: 'test2#email.com',active: false}],},{name: 'User2',configuration: [ {email: 'test3#email.com',active: true},{email: 'test4#email.com',active: true}],},];
const result = users.flatMap(user => user.configuration.filter( x => x.active===true));
console.log(result);
I have two objects.
one is defaultValue object that not gonna be changed and the another is comparedValue that can be changed.
const defaultValues = {
adminProfile: "Option 1",
channel: {id: 0, name: ''},
datetime: moment().format("yyyy-MM-DDTHH:mm:ssz"),
memo: '',
phoneNumber: 'none',
register: 'yes',
source: {id: 0, name: ''},
starred: false,
studio: 'common',
subject: {id: 0, name: ''},
}
const comparedValues = {
adminProfile: "Option 1",
channel: {id: 0, name: ''},
datetime: moment().format("yyyy-MM-DDTHH:mm:ssz"),
memo: '',
phoneNumber: 'none',
register: 'yes',
source: {id: 0, name: ''},
starred: false,
studio: 'common',
subject: {id: 0, name: ''},
}
If one of value of property is different than another, function returns false.
Here is the code that I wrote
const validation = (comparedValues) => {
return Object.keys(defaultValues).some(value => {
if (comparedValues.hasOwnProperty(value)) {
if (typeof comparedValues[value] === 'object') {
comparedValues[value].id === defaultValues[value].id
}
comparedValues[value] === defaultValues[value]
}
})
};
However this function always return true, how to make function compares two objects and other values one by one and returns false when it catches difference?
There are two issues here:
The first one is that you do not return true or false from the callback passed to .some().
The second one is that you use .some() which returns true if at least one item in the array suits the condition. However, you need to check all of them to be equal. It means you need to use .every() instead of some().
To fix everything, add the return statement into callback and use every():
const validation = (comparedValues) => {
return Object.keys(defaultValues).every(value => {
if (comparedValues.hasOwnProperty(value)) {
if (typeof comparedValues[value] === 'object') {
return comparedValues[value].id === defaultValues[value].id
}
return comparedValues[value] === defaultValues[value]
}
})
};
Now validation function will return true if ALL default values are equal to compared values.
Simple way to compare two objects :D
const compare = (objectA, objectB) => {
return JSON.stringify(objectA) === JSON.stringify(objectB);
}
My data set:
{
courseID003: {
studentID34: {
assigned: false
dueDate: null
}
studentID34: {
assigned: false
dueDate: null
}
}
courseID007: {
studentID89: {
assigned: true
dueDate: "2018-12-07 15:51"
}
studentID111: {
assigned: true
dueDate: "2018-12-07 15:51"
}
studentID115: {
assigned: false
dueDate: null
}
}
}
Question:
I have a number of course objects that contain student objects. Each course could contain a different number of students.
I need to search every course and every student to see if the assigned property is set to true.
Ideally, I'd like to call a function that performs this search and simply returns true or false. When searching, as soon as an assigned property is found set to true, the search would exit and return true. If all assigned properties are set to false for every student in every course, then return false.
I hope this question makes sense and I hope the data set makes sense/properly formatted ( I am dealing with all objects -- no arrays). All the course objects are in an object.
Thanks in advance for any help!
Here you are!
const data = {
courseID003: {
studentID34: {
assigned: false,
dueDate: null
},
studentID34: {
assigned: false,
dueDate: null
}
},
courseID007: {
studentID89: {
assigned: true,
dueDate: "2018-12-07 15:51"
},
studentID111: {
assigned: true,
dueDate: "2018-12-07 15:51"
},
studentID115: {
assigned: false,
dueDate: null
}
}
}
const search = (data) => {
return Object.keys(data).some(courseKey => {
return Object.keys(data[courseKey]).some(studentKey => {
return data[courseKey][studentKey]['assigned']
})
})
}
console.log(search(data))
Reference: some, Object.keys
You're going to have a bad time searching through that data as written. The real issue is your choice of data structure. In two places, you are using an object when you should be using an array.
Here is the same data but with courses encoded as an array, which is traversable with the rich set of array methods. I've made the same change to the collection of students for each course.
let courses = [
{
id: 'courseID003',
students: [
{
id: 'studentID34',
assigned: false,
dueDate: null
},
{
id: 'studentID34',
assigned: false,
dueDate: null
}
]
},
{
id: 'courseID007',
students: [
{
id: 'studentID89',
assigned: true,
dueDate: "2018-12-07 15:51"
},
{
id: 'studentID111',
assigned: true,
dueDate: "2018-12-07 15:51"
},
{
id: 'studentID115',
assigned: false,
dueDate: null
}
]
}
];
let unassignedStudents = Array.prototype.concat.apply(
[],
courses.map(c => c.students.filter(s => !s.assigned)));
console.log('unassignedStudents:',unassignedStudents);
With this improved data structure, you can find all 'unassigned' students like this:
let unassignedStudents = Array.prototype.concat.apply(
[],
courses.map(c => c.students.filter(s => !s.assigned)));
Hopefully you can see how this change in structure opens new doors for you.
Good luck.
This should do the trick, keep in mind Object.values might require a polyfill (for IE) as well as flatMap (missing in many browsers atm).
const courses = Object.values(data);
const students = courses.flatMap(course => Object.values(course);
const result = students.some(student => student.assigned);
I'm getting a JSON structure from an API, that I want to change in my front end. The frontend adds a property to the JSON structure, "isHidden". When I send the modified JSON back, I don't want the object that has "isHidden" to be sent back to the API, but I will still save that internally in my own mongodb.
However, doing this was aperently a bit harder then I thought. I made this function wich works but I think is very ugly:
function removeHiddenObject(data,parent){
for(var property in data){
if(data.hasOwnProperty(property)){
if(property == "isHidden" && data[property] === true){
parent.splice(parent.indexOf(data), 1);
}
else {
if(typeof data[property] === "object") {
removeHiddenObject(data[property], data);
}
}
}
}
return data;
}
It's a recursive method, but I find it way to complex and weird. Is there a way of simplifying my task?
Here is a jsfiddle for you if you'd like to help out: https://jsfiddle.net/vn4vbne8/
use this code to remove it from json string :
myJson=s.replace(/,*\s*"[^"]"\s*\:\s*{(.*?)"isHidden"\:([^}]*)}/gm,"");
Be careful in Regex every character is important so use exactly above code.
It removes every property that have an object that one of its properties is isHidden.
Javascript actually supports non-enumerable public properties. I'm assuming that when you send data back to the server you first stringify it with JSON.stringify which will only stringify public enumerable properties of the object.
You can define a non-enumerable property like this (more on this here):
Object.defineProperty(obj, 'isHidden', {
enumerable: false,
writable: true
});
Where obj is the javascript object you want to add the property to and isHidden is the name of the property you are adding. When done this way, the new property is accessible as obj.isHidden but nevertheless will not show up in JSON.stringify output nor in for loops.
Here is a solution using object-scan. Takes a bit of time to wrap your head around it, but it helps with some heavy lifting around general data processing.
// const objectScan = require('object-scan');
const data = {"user":{"name":"Bob"},"buildingBlockTree":[{"uid":"a875ed6cf4052448f9e0cc9ff092a76d4","_id":"56a7353f682e1cc615f4a6ae","columns":[{"uid":"a0061fdd2259146bb84e5362eeb775186","_id":"56a7353f682e1cc615f4a6b1","buildingBlocks":[{"user":{"name":"lajdi"},"buildingBlockTree":[{"uid":"a875ed6cf4052448f9e0cc9ff092a76d4","_id":"56a7353f682e1cc615f4a6ae","columns":[{"uid":"a0061fdd2259146bb84e5362eeb775186","_id":"56a7353f682e1cc615f4a6b1","buildingBlocks":[]},{"uid":"abbcf3328854840deb96bb6b101df2b39","_id":"56a7353f682e1cc615f4a6af","buildingBlocks":[{"uid":"a931cf745d4b847ba9cdc7f4b830413be","_id":"56a7353f682e1cc615f4a6b0","source":{"limit":1,"itemsListId":1,"offset":0}}]}],"template":{"name":"Xs12Sm12Md6Lg12DotXs12Sm12Md6Lg12"}}],"_id":"56a7353f682e1cc615f4a6ad","source":{"limit":1,"itemsListId":1,"offset":0},"template":{"numberOfColumns":1},"uid":"a5f6a2fd1c80f49c0b97e0c7994400588"}]},{"uid":"abbcf3328854840deb96bb6b101df2b39","_id":"56a7353f682e1cc615f4a6af","buildingBlocks":[{"_id":"56a7353f682e1cc615f4a6b0","source":{"limit":1,"itemsListId":1,"offset":0},"isHidden":true}]}]}],"_id":"56a7353f682e1cc615f4a6ad","source":{"limit":1,"itemsListId":1,"offset":0},"uid":"a5f6a2fd1c80f49c0b97e0c7994400588","metadata":{"title":"sss"},"title":"sss","url":"sss"};
const removeHiddenObjects = (input) => objectScan(['**[*].isHidden'], {
rtn: 'count',
filterFn: ({ value, gparent, gproperty }) => {
if (value === true) {
gparent.splice(gproperty, 1);
return true;
}
return false;
}
})(input);
console.log(removeHiddenObjects(data)); // counts removals
// => 1
console.log(data);
/* => {
user: { name: 'Bob' },
buildingBlockTree: [ {
uid: 'a875ed6cf4052448f9e0cc9ff092a76d4',
_id: '56a7353f682e1cc615f4a6ae',
columns: [ {
uid: 'a0061fdd2259146bb84e5362eeb775186',
_id: '56a7353f682e1cc615f4a6b1',
buildingBlocks: [ {
user: { name: 'lajdi' },
buildingBlockTree: [ {
uid: 'a875ed6cf4052448f9e0cc9ff092a76d4', _id: '56a7353f682e1cc615f4a6ae', columns: [
{ uid: 'a0061fdd2259146bb84e5362eeb775186', _id: '56a7353f682e1cc615f4a6b1', buildingBlocks: [] },
{ uid: 'abbcf3328854840deb96bb6b101df2b39', _id: '56a7353f682e1cc615f4a6af', buildingBlocks: [
{ uid: 'a931cf745d4b847ba9cdc7f4b830413be', _id: '56a7353f682e1cc615f4a6b0', source: {
limit: 1,
itemsListId: 1,
offset: 0
} }
] }
],
template: { name: 'Xs12Sm12Md6Lg12DotXs12Sm12Md6Lg12' }
} ],
_id: '56a7353f682e1cc615f4a6ad',
source: { limit: 1, itemsListId: 1, offset: 0 },
template: { numberOfColumns: 1 },
uid: 'a5f6a2fd1c80f49c0b97e0c7994400588'
} ]
}, { uid: 'abbcf3328854840deb96bb6b101df2b39', _id: '56a7353f682e1cc615f4a6af', buildingBlocks: [] } ]
} ],
_id: '56a7353f682e1cc615f4a6ad',
source: { limit: 1, itemsListId: 1, offset: 0 },
uid: 'a5f6a2fd1c80f49c0b97e0c7994400588',
metadata: { title: 'sss' },
title: 'sss',
url: 'sss'
}
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#16.0.0"></script>
Disclaimer: I'm the author of object-scan