So I have an array of objects called products:
const products = [
{
name: 'Pants'
},
{
name: 'Shoes'
},
{
name: 't shirts'
}
]
And the list contains a lot more products with other values apart from name. So suppose i forgot to give each product, (object) a coupon's array, it would take me quite a while to update each object manually.
Is there a function that I can create which will push a coupons value into each object as an array?
So the final array would look like:
const updatedProducts = [
{
name: 'Pants',
coupons: []
},
{
name: 'Shoes',
coupons: []
},
{
name: 't shirts',
coupons: []
}
]
const updatedProducts = products.map(product => ({ ...product, coupons: [] }))
Yes you can add properties in javascript like this:
products.forEach(product => product.coupons = []);
Related
What I am trying to achieve is:
Find if the text object within array is empty.
If criteria from no1 is matched, then return id value that sits in the top level of that object.
https://codesandbox.io/s/cranky-swirles-gb6ct?file=/src/App.js:410-412
In the code sandbox's example I have added two objects, with empty text strings and in that case I would expect to get an array of strings back (result = ['662e4120', '782h7a9x'])
I am able to find empty values, however I am not sure how to return object from the upper scope.
If you can't access the codeSandbox, snippet is attached just below:
const array = [
{
id: "5548d3c2",
state: {
properties: [
{
text: "text",
key: "fs5a"
}
]
}
},
{
id: "662e4120",
state: {
properties: [
{
text: "",
key: "m03n"
}
]
}
},
{
id: "782h7a9x",
state: {
properties: [
{
text: "",
key: "y5x1"
}
]
}
}];
const findItem = () => {
return array
.map((item) => item.state)
.map((item) => item.properties)
.flat()
.filter((item) => item.text === "");
};
Try to do something like this https://codesandbox.io/s/jovial-mcnulty-2fwh4
export default function App() {
const array = [
{
id: "5548d3c2",
state: {
properties: [
{
text: "text",
key: "fs5a"
}
]
}
},
{
id: "662e4120",
state: {
properties: [
{
text: "",
key: "m03n"
}
]
}
},
{
id: "782h7a9x",
state: {
properties: [
{
text: "",
key: "y5x1"
}
]
}
}
];
const findItem = () => {
return array.filter(obj=>obj.state.properties[0].text==="").map(obj=>obj.id)
};
console.log(findItem());
return <div className="App"></div>;
}
Here, we are filtering on the original array based on a predicate which is obj=>obj.state.properties[0].text==="". This basically get all the elements of the array which satisfy this predicate function. After this we are just applying map over the result to get the ids of the array elements satisfying this predicate function.
To get an array with the ids of the objects with no text you have to change the order or your iterations.
.filter() the array for the elements with empty text fields.
.map() the remaining elements to the values you are aiming for
When mapping or filtering you can't just go one but as many levels deep as you like. Since 'properties' holds an array and you want the first element, you can access that with the index array[0] (with that the flat() you did is superfluous)
const findItem = () => {
return array
.filter(item => item.state.properties[0].text === "") // (2) [{…}, {…}] the original items with no text
.map(item => item.id) // ['662e4120', '782h7a9x']
};
(code might be as well embedded as a snippet, which can be run directly)
const array = [
{
id: "5548d3c2",
state: {
properties: [
{
text: "text",
key: "fs5a"
}
]
}
},
{
id: "662e4120",
state: {
properties: [
{
text: "",
key: "m03n"
}
]
}
},
{
id: "782h7a9x",
state: {
properties: [
{
text: "",
key: "y5x1"
}
]
}
}];
const findItem = () => {
return array
.filter(item => item.state.properties[0].text === "") // (2) [{…}, {…}] the original items with no text
.map(item => item.id) // ['662e4120', '782h7a9x']
};
console.log(findItem())
when a value of a property of the object is null or contains "missing" the whole object should be filterd.
this works for filtering null
object = (object.filter(o => !Object.values(o).includes(null))
But how can I add 2 filters and how to implement a filter that filters strings that contain the word "missing"
object = (object.filter(o => !Object.values(o).includes(null) | ("missing")));
object:
[
{ id: 'blockstack-iou',
name: 'Blockstack (IOU)',
image: 'missing_large.png'
}
{ id: 'qtum',
name: 'Qtum',
image:
'https://assets.coingecko.com/coins/images/684/large/qtum.png?1547034438',
price_change_percentage: -53.2869774915231
}
]
Use Array.prototype.every().
Use && to combine multiple tests.
let object = [{
id: 'blockstack-iou',
name: 'Blockstack (IOU)',
image: 'missing_large.png'
},
{
id: 'qtum',
name: 'Qtum',
image: 'https://assets.coingecko.com/coins/images/684/large/qtum.png?1547034438',
price_change_percentage: -53.2869774915231
}
];
console.log(object.filter(o => Object.values(o).every(prop =>
prop != null && !prop.toString().includes("missing"))));
Use && and match
const object = [
{id: 'blockstack-iou',
name: 'Blockstack (IOU)',
image: 'missing_large.png'
},
{ id: 'qtum',
name: 'Qtum',
image:
'https://assets.coingecko.com/coins/images/684/large/qtum.png?1547034438',
price_change_percentage: -53.2869774915231
}
]
const filtered = (object.filter(o =>!Object.values(o).includes(null) && !Object.values(o).toString().match(/missing/gi)));
console.log(filtered)
If you're looking for a solution that is easily extensible, consider storing all your "conditions" as an array and running through them using .every().
const object = [
{str: "this_is_missing"},
{str: null},
{str: "valid"}
];
const validations = [
i => i !== null, //Value isn't null
i => !i.toString().includes("missing") //Value doesn't contain "missing"
];
const validate = (val) => validations.every(fn => fn(val));
const result = object.filter(obj => Object.values(obj).every(validate));
console.log(result);
I have an object with an array of families. Each one of these families holds an array of family member objects. Each of the family members has a contract which is not present right now. My task is to fetch the contract from a rest api and to merge it into the member object.
Object {
content: [{
familiId: '1',
familyMemmbers: [
{ id: '1'
name: 'Tom'
...
},
{ id: '2'
name: 'Peter'
...
}
]
},
{
familiId: '2',
familyMemmbers: [
{ id: '1'
name: 'Paul'
...
},
{ id: '2'
name: 'Joe'
...
}
]
}]
}
this.service.getFamilies().switchMap(familiyPage => from(familiyPage.content))
.switchMap(family => from(family.familyMembers)).mergeMap(member => this.service.getContract(member.id).map(contract => {
return {...member, contract}
My approach returns the object { id: 1, name: 'Tom', contract: ....} on the first emit and { id: 2, name: 'Peter', contract: ....} on the second emit, { id: 1, name: 'Paul', contract: ....} on the third emit and { id: 2, name: 'Joe', contract: ....} on the fourth emit.
What i would like to have is that there is only one emit which contains the whole data structure. i.e.
Object {
content: [{
familiId: '1',
familyMemmbers: [
{ id: '1',
name: 'Tom',
contract: {...},
...
},
{ id: '2',
name: 'Peter',
contract: {...},
...
}
]
}, ...]
}
Use forkJoin to group the array of observable members into an observable array of members. Then use toArray to group the observable families into an observable array of families. Use mergeMap if you do not care about the order of the families, or concatMap if you want to keep the families in their original order.
this.service.getFamilies().pipe(
// use concatMap instead of mergeMap if you want to keep the families in their original order
mergeMap(family => {
// array of observables
const members$ = family.familyMembers.map(member => {
return getContract(member.id).pipe(map(contract => {...member, contract});
});
// use forkJoin to return single observable that returns array of results
return forkJoin(members$).pipe(map(familyMembers => {...family, familyMembers}));
}),
// combine all the families back into an array of families
toArray());
you're operating on arrays within an array, so you need nested forkJoins to accomplish this along with multiple assignments.
this.service.getFamilies().pipe(
switchMap(familiesData =>
forkJoin(
familiesData.content.map(family =>
forkJoin(
family.members.map(member =>
this.service.getContract(member.id).pipe(
map(contract => Object.assign({}, member, {contract})) // assign contract
)
)
).pipe(
map(familyMemmbers => Object.assign({}, family, {familyMemmbers})) // assign members
)
)
).pipe(
map(content => Object.assign({}, familiesData, {content})) // assign content
)
)
);
step by step:
get families
switchMap to forkJoin of
content mapped into a forkJoin of
family members mapped into getContract
assign resulting contracts to members and return members with contracts
assign resulting familyMembers to families and return families with familyMembers
assign resulting families to content and return new content
Just add rxjs pipeAble operator toArray() this will combine all the emitted
you can see the below code, where we are streaming the array of objects then streams family members and request HTTP call for each family member then map the response with the family member Object.than again mapping the resultant family Members with the family object and merge them using toArray().
const appDiv = document.getElementById('app');
appDiv.innerHTML = `<h1>if you dont want concurrent request then you can use concat instead of merge</h1>`;
const { fromEvent, merge, of, from } = rxjs;
const { map, filter, concatMap, toArray, tap, delay, concatAll, mergeMap,mergeAll } = rxjs.operators;
// Write TypeScript code!
console.clear();
const data$ = of([{
familiId: '1',
familyMemmbers: [
{ id: '1',
name: 'Tom'
},
{ id: '2',
name: 'Peter'
}
]
},
{
familiId: '2',
familyMemmbers: [
{ id: '1',
name: 'Paul'
},
{ id: '2',
name: 'Joe'
}
]
}])
const q = (x) => {
// Fake http call
const oneSecondSource$ = of(x['id']).pipe(delay(1 * x.id))
return oneSecondSource$.pipe(map(abs => {
return { ...x, contarct: x['id'] + x['name'] }
}));
}
const p = (obj) => {
// mapping each
return from(obj.familyMemmbers).pipe(mergeMap(q), toArray(), map(a => {
return { ...obj, familyMemmbers: a }
}))
}
const example$ = data$.pipe(mergeMap(a => from(a).pipe(map(p))),
mergeAll(),
toArray()
);
example$.subscribe(console.log)
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
<div id="app"></div>
For your Question click here for Stackblitz solution
i want to access the id 'qwsa221' without using array index but am only able to reach and output all of the array elements not a specific element.
i have tried using filter but couldnt figure out how to use it properly.
let lists = {
def453ed: [
{
id: "qwsa221",
name: "Mind"
},
{
id: "jwkh245",
name: "Space"
}
]
};
Use Object.keys() to get all the keys of the object and check the values in the array elements using . notation
let lists = {
def453ed: [{
id: "qwsa221",
name: "Mind"
},
{
id: "jwkh245",
name: "Space"
}
]
};
Object.keys(lists).forEach(function(e) {
lists[e].forEach(function(x) {
if (x.id == 'qwsa221')
console.log(x)
})
})
You can use Object.Keys method to iterate through all of the keys present.
You can also use filter, if there are multiple existence of id qwsa221
let lists = {
def453ed: [
{
id: "qwsa221",
name: "Mind"
},
{
id: "jwkh245",
name: "Space"
}
]
};
let l = Object.keys(lists)
.map(d => lists[d]
.find(el => el.id === "qwsa221"))
console.log(l)
you can do it like this, using find
let lists = {
def453ed: [
{
id: "qwsa221",
name: "Mind"
},
{
id: "jwkh245",
name: "Space"
}
]
};
console.log(
lists.def453ed // first get the array
.find( // find return the first entry where the callback returns true
el => el.id === "qwsa221"
)
)
here's a corrected version of your filter :
let lists = {def453ed: [{id: "qwsa221",name: "Mind"},{id: "jwkh245",name: "Space"}]};
// what you've done
const badResult = lists.def453ed.filter(id => id === "qwsa221");
/*
here id is the whole object
{
id: "qwsa221",
name: "Mind"
}
*/
console.log(badResult)
// the correct way
const goodResult = lists.def453ed.filter(el => el.id === "qwsa221");
console.log(goodResult)
// filter returns an array so you need to actually get the first entry
console.log(goodResult[0])
I didn't find the answer here, so please to do no write that it is duplicate!
My problem is as follows. I have such an array with objects:
Items: [
{ groups: [{…}]
id: 1
name: "Test Name"
_test: null
_test2: 0.02867696
},
{ groups: [{…}]
id: 2
name: "Test Name2"
_test: null
_test2: 0.02867696
},
]
I need to change each object fields names, such as id, name to topicId and topicName. The rest on the data I need to keep as it is and return back array with changed objects.
I wrote such a function to get access to every object:
function changeFields(data) {
for (const key of Object.keys(data)) {
data[key].map(item => {
})
}
}
but I do not know what to do next.
As per your question you are trying to modify existing array of objects. Below are the pseudo steps
Loop through array using map or any equivalent method
Clone the object
Add new property with desired key to cloned object and it's value will be value associated with existing key
Delete old key from the object
Below is the sample code for your data and in that code i am modifying key id to _id
var data = [
{
groups: [{}],
id: 1,
name: "Test Name",
_test: null,
_test2: 0.02867696
},
{
groups: [{}],
id: 2,
name: "Test Name2",
_test: null,
_test2: 0.02867696
}
];
var modifiedData = data.map((item) => {
let _item = Object.assign(item, {});
_item['_id'] = item['id'];
delete _item['id'];
return _item;
});
console.log(modifiedData);
You can use map method of array to modify each entry and reassign it.
let Items = [
{
groups: [
1, 2
],
id: 1,
name: "Test Name",
_test: null,
_test2: 0.02867696
}, {
groups: [
1, 2
],
id: 2,
name: "Test Name2",
_test: null,
_test2: 0.02867696
}
]
Items = Items.map(item => ({
group : item.group,
topicId : item.id,
topicName : item.name,
_test : item._test,
_test2 :item._test2
}))
Or you have many field in array and only want to change one or two filed you can write general solution like this :
Items = Items.map(item => {
let obj = {};
//Loop trough each fields of item
Object.keys(item).filter(key => {
switch (key) {
//Fields to be changed
case 'id':
obj['topicId'] = item['id']
break;
case 'name':
obj['topicName'] = item['name']
break;
//End
//Rest will be the same
default:
obj[key] = item[key]
}
})
//Return modified obj
return obj;
})