Make a new object from an array of objects [duplicate] - javascript

This question already has answers here:
Create an object with dynamic property names [duplicate]
(2 answers)
Closed 6 years ago.
This is possibly a duplicate, but everywhere I search I can only seem to find people wanting to create an array of objects.
Basically I'm trying to achieve the opposite, pull certain values of an array of objects out into an object. It's twisting my head a little so any of you JS gurus out there if you could give me a hand it would be very very appreciated!
Basically I have an array of objects like this:
[
{ field: 'name', value: 'sam', isRequired: true },
{ field: 'email', value: 'sam#dummyemail.net', isRequired: true },
{ field: 'message', value: 'hey', isRequired: false },
]
They're split up this way because I go through the fields for validation.
After the validation phase I want to map the field and value properties to name value pairs within a new object e.g:
{
name: 'sam',
email: 'sam#dummyemail.net',
message: 'hey',
}
Like I said any help would be amazing! Cheers.

Array#map each object in the array into a new object with field as the key of a property, and value, well, the value of the property. Then combine the new objects array to object using the spread syntax and Object#assign:
const arr = [
{ field: 'name', value: 'sam', isRequired: true },
{ field: 'email', value: 'sam#dummyemail.net', isRequired: true },
{ field: 'message', value: 'hey', isRequired: false },
];
const result = Object.assign({}, ...arr.map(({ field, value }) => ({ [field]: value })));
console.log(result);

you could map array into object like this
var array = [
{ field: 'name', value: 'sam', isRequired: true },
{ field: 'email', value: 'sam#dummyemail.net', isRequired: true },
{ field: 'message', value: 'hey', isRequired: false },
];
var object = {};
array.forEach(x => {
object[x.field] = x.value;
});
console.log(object);

Related

filter an array based on another array inside the main one [duplicate]

This question already has answers here:
Filter an array to return matching id's of a nested array in JavaScript [duplicate]
(2 answers)
Filtering array of objects with arrays based on nested value
(8 answers)
Closed 2 months ago.
I have an array of data similar to this structure:
const array = [
{
name: 'name',
tags: [
{
name: 'xxxx',
url: '/this',
},
],
},
{
name: 'name',
tags: [
{
name: 'xxxxxxx',
url: '/that',
},
],
},
];
I would like to return for example, the objects that contain only the url:'this'.
i tried to map the outer array first, and then using filter in the nested tag array, but without any luck. Any suggestions?
thanks
This works even when tags has multiple objects in its array
const arr = [{
name: 'name',
tags: [{
name: 'xxxx',
url: '/this'
}]
}, {
name: 'name',
tags: [{
name: 'xxxxxxx',
url: '/that'
}]
}]
console.log(arr.filter((item) => item.tags.some((tag) => tag.url === "/this")))

How to map JSON Object to array with keys in javascript

There's about million questions (and answers) out there on this topic, but none of them are doing what I need to do. I have a JSON object where the value for each key is an object. I want to convert this to an array and maintain the top level keys.
{
"someKey1": {
active: true,
name: "foo"
},
"someKey2": {
active: false,
name: "bar"
}
}
If I use Object.keys() I get the top level keys, but not their values. If I use Object.values() I get an array with all the values, but not their keys. I'm trying to use keys and map, but am only getting the values returned:
const data = {
"someKey1": {
active: true,
name: "foo"
},
"someKey2": {
active: false,
name: "bar"
}
}
const items = Object.keys(data).map(function(key) {
return data[key];
});
// returns [{active: true, name: foo},{active: false, name: bar}]
Is there a way to get both? I want to get an array I can iterate over that looks something like this:
[{
key: someKey1,
active: true,
name: "foo"
},
{
key: someKey2,
active: true,
name: "foo"
}]
OR
[
"someKey1": {
active: true,
name: "foo"
},
"someKey2": {
active: false,
name: "bar"
}
]
I think you are going in the right direction, if you want to add the "key" property you have to map the properties manually and for the second option since you don't need the "key" property it can be done a little bit more elegantly:
For the first option:
Object.keys(data).map(v => ({
key: v,
...data[v]
}));
For the second option even simpler:
Object.keys(data).map(v => ({[v]: {...data[v]}}))
You can easily map your data to a new object:
Object.keys(data).map(key => ({ ...data[key], "key": key }));

Vue JS lodash findKey nested object with dot notation returns undefined

I'm trying to pull out a value for a nested object key from some eligibility array that I've got, but I'm getting an undefined value for some reason and need to know what I'm missing.
Given the following array:
const eligibilityCriteria = [
{ field: 'loan.amount', operator: '>=', value: 1000 },
{ field: 'loan.term', operator: '>=', value: 1 },
{ field: 'applicant.birthday', operator: '>=', value: 40 },
{ field: 'applicant.isHomeowner', operator: '==', value: false }
]
I need to find loan.amount from a nested object and pull out it's value:
My big nested object is (coming from the store)
application: {
meta: {
brand: '',
version: '',
affiliate: '',
affiliate_full: '',
campaign: '',
client_hostname: '',
client_href: '',
client_origin: '',
client_useragent: '',
client_ip: '127.0.0.1',
icicle_hash: ''
},
loan: {
amount: 500,
term: null,
purpose: null
}
}
My function right now is:
checkEligibility () {
const eligibilityCriteria = [
{ field: 'loan.amount', operator: '>=', value: 1000 },
{ field: 'loan.term', operator: '>=', value: 1 },
{ field: 'applicant.birthday', operator: '>=', value: 40 },
{ field: 'applicant.isHomeowner', operator: '==', value: false }
]
for (const [index, offer] of this.datasets.offers.entries()) {
const eligibility = eligibilityCriteria
if (eligibility) {
for (const [ci, criteria] of eligibility.entries()) {
// TODO: this fails to pull the value, returns undefined
const field = _.findKey(this.$store.state.application.application, criteria.field)
}
}
}
}
What am I missing?
You must have to misunderstood what _.findKey() does
This method is like _.find except that it returns the key of the first element predicate returns truthy for instead of the element itself.
See Example 2 in the code below.
If you want to retrieve the value from the object at a given path, you must use _.property() (Example 2 below)
const eligibilityCriteria = [
{ field: 'loan.amount', operator: '>=', value: 1000 },
{ field: 'loan.term', operator: '>=', value: 1 },
]
const application = {
loan: {
amount: 500,
term: 2,
amount2: 0,
}
}
// example 1
// outputs "loan"
console.log(_.findKey(application, "amount"))
// outputs undefined - there is no key in application object that has property chain "loan.amount"
console.log(_.findKey(application, "loan.amount"))
// outputs undefined - "amount2" key is there but the value is falsy
console.log(_.findKey(application, "amount2"))
// example 2
for (const [ci, criteria] of eligibilityCriteria.entries()) {
console.log(criteria.field, _.property(criteria.field)(application))
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>

How do I preserve the order of this javascript array sort?

const modules = [
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
]
I am trying to sort the array so that the True values come first , then False values.
const orderedModules = modules.sort((a, b) => (a.checked ? -1 : 1))
However, I'd like to preserve the order of the True values. The code above sometimes puts Air first, then Earth (if ran twice). How can I preserve the order all the time?
The callback used as the compare function can return 3 options: negative number, positive number or zero. The negative number indicates that the first parameter should be before the second parameter in the array order. The positive number indicates that the first parameter should be after the second parameter in the array order. And zero means that the order should be kept as is.
Sort array method on MDN
If you want to order just the true values first in the same order in the array and then the false values, probably adding more logic to return zero from the compare function if both are true will solve your issue.
Here is an example:
const modules = [
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
];
modules.sort((a,b) => a.checked && b.checked ? 0 : a.checked ? -1 : 1);
console.log(modules);
If you don't mind creating a new array, just iterate over the array twice. The first time, push to the new array the objects with the true values as the iteration encounters them. The second time, push the objects with the false values. (JavaScript passes objects by reference so the new array won't cause them to get duplicated.)
Probably this might help you. not sure for optimize way but this function iterate over an array one time only.
I am using reduce function to separate out true and false values and then return them in the order you want.
const shortItems = (array) => {
const orderedModulesObject = array.reduce((orderedModulesObject, currentModule) => {
if(currentModule.checked){
orderedModulesObject.trueValues = orderedModulesObject.trueValues.concat(currentModule);
} else {
orderedModulesObject.falseValues = orderedModulesObject.falseValues.concat(currentModule);
}
return orderedModulesObject;
}, { trueValues: [], falseValues: []});
return orderedModulesObject.trueValues.concat(orderedModulesObject.falseValues);
}
const modules = [
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
]
console.log(shortItems(modules));
the reason is that sort actually changes the original array. Although modules is defined with const, the values inside can change, as long as you don't assign the variable to something else.
according to this answer, you can sort without mutating the original using spread syntax. this code should work:
const orderedModules = [...modules].sort((a, b) => (a.checked ? -1 : 1))
to make an array or object not able to be modified, you can use Object.freeze()
const modules = Object.freeze([
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
])
Edit: I just realized the order isn't correct, but it at least is the same every time. but that's because the sorting isn't exactly right. here's the correct code:
const orderedModules = [...modules].sort((a, b) => (a.checked != b.checked ? (a.checked ? -1 : 1 ) : 0))

How to validate object constraint in a object using joi?

I am trying object validation with the help of joi.
I want to validate object as a constraint inside an object like
let login = {
value: 0/1,
slots: [{ label: '', value: '24 hr'}, { label: '', value: '24 hr'}]
}
Here login is an object and inside it slots is also an object. So if I write like the following
const schema = Joi.object().keys({
value : Joi.number.required(),
slots : Joi.string.required()
});
would it be correct for object data type or should I replace string data type with object data type?
I want to validate object type as a constraint.
Your slots key needs to be an array of objects:
const schema = Joi.object().keys({
value: Joi.number().required(),
slots: Joi.array().items(
Joi.object().keys({
label: Joi.string().required().allow(''),
value: Joi.string().required()
})
)
})
This way, the following object will be valid:
const obj = {
value: 1,
slots: [
{
label: '',
value: '24 hr'
}
]
}

Categories