Find a value in an array of populated objects mongdb - lodash - javascript

Maybe this question is duplicate or asked several times in different ways but still haven't solved my problem. I am creating nodejs api returning 10,000 populated objects from mongodb. I want to filter array based on the object.
{color: red}
How can i use lodash filter to return array with containing specified filter object.
[
{
"value": 200,
"newEle": {
"gradient": "true",
"mode": {
"color": "red"
}
}
},
{
"value": 100,
"newEle": {
"gradient": "false",
"mode": {
"color": "blue"
}
}
}
]

If you are specifically trying to filter by just the color you can use vanilla JS's .filter() to get all the objects with the color property of red into a new array:
const arr = [
{
"value": 200,
"newEle": {
"gradient": "true",
"mode": {
"color": "red"
}
}
},
{
"value": 100,
"newEle": {
"gradient": "false",
"mode": {
"color": "blue"
}
}
}
],
color = "red",
res = arr.filter(obj => obj.newEle.mode.color === color);
console.log(res);
If you wish to use lodash specifically you can use _.filter():
const arr = [
{
"value": 200,
"newEle": {
"gradient": "true",
"mode": {
"color": "red"
}
}
},
{
"value": 100,
"newEle": {
"gradient": "false",
"mode": {
"color": "blue"
}
}
}
],
color = "red",
res = _.filter(arr, obj => obj.newEle.mode.color === color);
console.log(res);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

When using lodash, it's as simple as this.
let filtered_array = _.filter(myArr, { color: 'red' });
However, since you have nested nested objects, you'd want to create a predicate that accesses the nested value. You do this with an array.
let filtered_array = _.filter(myArr, ['newEle.mode.color', 'red']);

Related

Loop through an array of objects and update parent object count if child object exists

I am using Angular 13 and I have an array of objects like this:
[{
"name": "Operating System",
"checkedCount": 0,
"children": [{
"name": "Linux",
"value": "Redhat",
"checked": true
},
{
"name": "Windows",
"value": "Windows 10"
}
]
},
{
"name": "Software",
"checkedCount": 0,
"children": [{
"name": "Photoshop",
"value": "PS",
"checked": true
},
{
"name": "Dreamweaver",
"value": "DW"
},
{
"name": "Fireworks",
"value": "FW",
"checked": true
}
]
}
]
I would like to loop through the array, check if each object has a children array and it in turn has a checked property which is set to true, then I should update the checkedCount in the parent object. So, result should be like this:
[{
"name": "Operating System",
"checkedCount": 1,
"children": [{
"name": "Linux",
"value": "Redhat",
"checked": true
},
{
"name": "Windows",
"value": "Windows 10"
}
]
},
{
"name": "Software",
"checkedCount": 2,
"children": [{
"name": "Photoshop",
"value": "PS",
"checked": true
},
{
"name": "Dreamweaver",
"value": "DW"
},
{
"name": "Fireworks",
"value": "FW",
"checked": true
}
]
}
]
I tried to do it this way in angular, but this is in-efficient and results in an error saying this.allFilters[i].children[j] may be undefined. So, looking for an efficient manner to do this.
for(let j=0;i<this.allFilters[i].children.length; j++) {
if (Object.keys(this.allFilters[i].children[j]).length > 0) {
if (Object.prototype.hasOwnProperty.call(this.allFilters[i].children[j], 'checked')) {
if(this.allFilters[i].children[j].checked) {
this.allFilters[i].checkedCount++;
}
}
}
}
Use a nested for loop to check all the children. If checked is truthy, increment the count of the parent. You don't need to check if parent.children has any elements since if there are no elements the loop won't run anyways.
// minified data
const data = [{"name":"Operating System","checkedCount":0,"children":[{"name":"Linux","value":"Redhat","checked":!0},{"name":"Windows","value":"Windows 10"}]},{"name":"Software","checkedCount":0,"children":[{"name":"Photoshop","value":"PS","checked":!0},{"name":"Dreamweaver","value":"DW"},{"name":"Fireworks","value":"FW","checked":!0}]}];
for (const parent of data) {
for (const child of parent.children) {
if (child.checked) parent.checkedCount++;
}
}
console.log(data);
No need to complicate it like that, you just need to check checked property in children.
data.forEach((v) => {
v.children.forEach((child) => {
if (child.checked) {
v.checkedCount++;
}
});
});
Using filter + length on children array should do the job:
const data = [{"name":"Operating System","checkedCount":null,"children":[{"name":"Linux","value":"Redhat","checked":true},{"name":"Windows","value":"Windows 10"}]},{"name":"Software","checkedCount":null,"children":[{"name":"Photoshop","value":"PS","checked":true},{"name":"Dreamweaver","value":"DW"},{"name":"Fireworks","value":"FW","checked":true}]}];
data.forEach(itm => {
itm.checkedCount = itm.children?.filter(e => e.checked === true).length ?? 0;
});
console.log(input);
I would suggest going functional.
Using map
const children = arr.map(obj => obj.children);
const result = children.map((child, idx) => {
const checkedCount = child.filter(obj => obj.checked)?.length;
return {
...arr[idx],
checkedCount
};
});
console.log(result)
or using forEach
const result = [];
const children = arr.map(obj => obj.children);
children.forEach((child, idx) => {
const checkedCount = child.filter(obj => obj.checked)?.length;
result[idx] = {
...arr[idx],
checkedCount
};
});
console.log(result)

How to sort an array of objects based on scores - Javascript

I have an array of objects that contain the data I want to sort (it has more properties), like so:
[
{
"data": {
"id": "green"
}
},
{
"data": {
"id": "red"
}
},
{
"data": {
"id": "blue"
}
}
]
id is a nested property I need to use in order to sort based on scores provided from a different object like so:
{
"green": 5,
"red": 3,
"blue": 8
}
I'm trying to find the best way to sort my array of object, however no success so far.
Javascripts built-in sort function has a optional comparison function parameter.
The following code utilizes this function to solve your problem:
var array = [
{
"data": {
"id": "green"
}
},
{
"data": {
"id": "red"
}
},
{
"data": {
"id": "blue"
}
}
];
var scores =
{
"green": 5,
"red": 3,
"blue": 8
};
array.sort((a, b) => (scores[a.data.id] - scores[b.data.id]));
console.log(array);
You can sort them like this:
https://jsfiddle.net/Ldvja31t/1/
const scores = {
"green": 5,
"red": 3,
"blue": 8
};
const myData = [
{
"data": {
"id": "green"
}
},
{
"data": {
"id": "red"
}
},
{
"data": {
"id": "blue"
}
}
];
myData.sort((d1, d2) => {
return scores[d1.data.id] - scores[d2.data.id]
});
console.log(myData)
The two answers that were given should work fine. However I would also like to add you could use an Enum. Example
Heres a separate example of an enum usage and sorting it in an array of objects
const enum Order {
Start = 'Start',
Run = 'Run',
End = 'End',
}
const predicate = (a, b) => {
const map = {};
map[Order.Start] = 1;
map[Order.Run] = 2;
map[Order.End] = 3;
if (map[a] < map[b]) {
return -1;
}
if (map[a] > map[b]) {
return 1;
}
return 0;
}
const data = [Order.End, Order.Run, Order.Start];
const result = data.sort(predicate);
console.log(result);

Array item using its own parent object index as its value?

lets say we have :
let array_of_objects = [
{
"color": "purple",
"type": "minivan",
"id": this.object.index // i know this is not valid code,but can this somehow get its own index within the array as value ?
},
{
"color": "red",
"type": "station wagon",
"id": this.object.index //this should be 1
}
]
Actual question in code comments..
what i'm trying to do is to fill a form's inputs using an object,and i want to be able to display the actual index of the object within the array in one of the inputs
instead of using index as id I suggest create a complex id or you can use uuid() library for creating unique user id uuid npm
import { v4 as uuidv4 } from 'uuid';
array_of_objects = array_of_objects.map((item, index) => ({ id: uuidv4(), ...item}))
console.log(array_of_objects);
let array_of_objects = [
{
"color": "purple",
"type": "minivan"
},
{
"color": "red",
"type": "station wagon"
}
];
array_of_objects = array_of_objects.map((item, index) => ({ id: index, ...item}))
console.log(array_of_objects);
Just initialize the array without the id and add it afterwards using a for loop.
let array_of_objects = [
{
"color": "purple",
"type": "minivan",
},
{
"color": "red",
"type": "station wagon",
}
]
for (let i = 0; i < array_of_objects.length; i++) {
array_of_objects[i].id = i;
}
You can use Object.keys(arrayVarible) to get the indexes of array which outputs as an array as well.
let array_of_objects = [
{
"color": "purple",
"type": "minivan",
},
{
"color": "red",
"type": "station wagon",
}
];
console.log(Object.keys(array_of_objects))
Each time the the array changes or you fill the form run this code
console.log(array_of_objects.length-1)

map whole array if value equal

I would like to map an array where if one of the values equal to a variable then I change the isChecked key for all objects in this array. for e.g.
input array:
[
[
{
"name": "size",
"value": "XS",
"isChecked": false
},
{
"name": "colors",
"value": "black",
"isChecked": false
}
],
[
{
"name": "size",
"value": "XXXL",
"isChecked": false
},
{
"name": "colors",
"value": "brown",
"isChecked": false
}
],
[
{
"name": "size",
"value": "S",
"isChecked": false
},
{
"name": "colors",
"value": "green",
"isChecked": false
}
]
]
input value: black
output:
[
[
{
"name": "size",
"value": "XS",
"isChecked": true
},
{
"name": "colors",
"value": "black",
"isChecked": true
}
],
[
{
"name": "size",
"value": "XXXL",
"isChecked": false
},
{
"name": "colors",
"value": "brown",
"isChecked": false
}
],
[
{
"name": "size",
"value": "S",
"isChecked": false
},
{
"name": "colors",
"value": "green",
"isChecked": false
}
]
]
maybe should i use some callback,promise? How to map this array? I have to somehow return to the value I missed. In this case, if the value in the array is found then all elements in this array should be marked as isChecked = true.
i've got something like this now:
this.allVariants.map((variant, key) => {
return variant.map((opts, k) => {
if (opts.value == val && !opts.isChecked) {
let mapped = variant.map(op => op.isChecked = true);
} else {
let mapped = variant.map(op => op.isChecked = false);
}
return opts
})
})
You could use map method and inside some to check if element exists in sub-array or not.
const data = [[{"name":"size","value":"XS","isChecked":false},{"name":"colors","value":"black","isChecked":false}],[{"name":"size","value":"XXXL","isChecked":false},{"name":"colors","value":"brown","isChecked":false}],[{"name":"size","value":"S","isChecked":false},{"name":"colors","value":"green","isChecked":false}]]
const res = data.map(arr => {
const check = arr.some(({value}) => value == 'black');
return check ? arr.map(e => ({...e, isChecked: true})) : arr
})
console.log(res)
Perhaps you're looking for something like this? As you can see there's a simple map function which will return an array of the relevant values depending on what was input into the function. It will simply map over the provided arrray and update the relevant objects, provided that the find function doesn't return null.
It achieves this by seeing if the provided value can be found within a nested array via using the found function that I've implemented, provided this returns true, it will then use the mutate function. The idea was that you may want to further change different properties on the given object(s) in future, hence why it has a dedicated function.
My answer is similar to #NenadVracar only I broke it up a little more into multiple functions that consume a single line.
let data = [[{name:"size",value:"XS",isChecked:!1},{name:"colors",value:"black",isChecked:!1}],[{name:"size",value:"XXXL",isChecked:!1},{name:"colors",value:"brown",isChecked:!1}],[{name:"size",value:"S",isChecked:!1},{name:"colors",value:"green",isChecked:!1}]];
// A function that states if relevant object with value exists.
let found = v => a => a.some(({value}) => value == v);
// A function used to return data that has been changed, specifically isChecked = true.
let mutate = a => a.map(i => ({...i, isChecked: true}));
// A function to return the desired array, takes an array and a value.
let map = v => a => a.map(o => found(v)(o) ? mutate(o) : o);
console.log(map('black')(data));

How to iterate through deeply nested objects inside of a JSON?

I know there are plenty of questions about iterating through JSON objects but I haven't found one that quite relates to my exact problem. This is the JSON that I'm trying to iterate through:
psinsights = {
"kind": "pagespeedonline#result",
"id": "/speed/pagespeed",
"responseCode": 200,
"title": "PageSpeed Home",
"score": 90,
"pageStats": {
"numberResources": 22,
"numberHosts": 7,
"totalRequestBytes": "2761",
"numberStaticResources": 16,
"htmlResponseBytes": "91981",
"cssResponseBytes": "37728",
"imageResponseBytes": "13909",
"javascriptResponseBytes": "247214",
"otherResponseBytes": "8804",
"numberJsResources": 6,
"numberCssResources": 2
},
"formattedResults": {
"locale": "en_US",
"ruleResults": {
"AvoidBadRequests": {
"localizedRuleName": "Avoid bad requests",
"ruleImpact": 0.0
},
"MinifyJavaScript": {
"localizedRuleName": "Minify JavaScript",
"ruleImpact": 0.1417,
"urlBlocks": [
{
"header": {
"format": "Minifying the following JavaScript resources could reduce their size by $1 ($2% reduction).",
"args": [
{
"type": "BYTES",
"value": "1.3KiB"
},
{
"type": "INT_LITERAL",
"value": "0"
}
]
},
"urls": [
{
"result": {
"format": "Minifying $1 could save $2 ($3% reduction).",
"args": [
{
"type": "URL",
"value": "http://code.google.com/js/codesite_tail.pack.04102009.js"
},
{
"type": "BYTES",
"value": "717B"
},
{
"type": "INT_LITERAL",
"value": "1"
}
]
}
},
{
"result": {
"format": "Minifying $1 could save $2 ($3% reduction).",
"args": [
{
"type": "URL",
"value": "http://www.gmodules.com/ig/proxy?url\u003dhttp%3A%2F%2Fjqueryjs.googlecode.com%2Ffiles%2Fjquery-1.2.6.min.js"
},
{
"type": "BYTES",
"value": "258B"
},
{
"type": "INT_LITERAL",
"value": "0"
}
]
}
}
]
}
]
},
"SpriteImages": {
"localizedRuleName": "Combine images into CSS sprites",
"ruleImpact": 0.0
}
}
},
"version": {
"major": 1,
"minor": 11
}
};
Now, I'm trying to write a function that iterates through all of the ruleResults objects and returns an array of the localizedRuleName properties. According to the JSON, ruleResults has three member objects (AvoidBadRequests, MinifyJavaScript, and SpriteImages). Each of these has a localizedRuleName property I'm trying to access, but when I print out my array, it's blank. Here's how I've written my function:
function ruleList(results) {
var ruleArray = [];
for(var ruleName in results.formattedResults.ruleResults){
ruleArray[counter] = results.formattedResults.ruleResults[ruleName].localizedRuleName;
}
return ruleArray;
}
console.log(ruleList(psinsights));
Can you guys help me get on the right track? I used basically this same method to iterate through the pageStats of the JSON and it worked perfectly. I'm not sure why I can't get it to work with these deeper nested objects and properties.
your problem is not your iteration, but your undefined variable "counter".
Instead of using a counter can use the "push" function:
function ruleList(results) {
var ruleArray = [];
for(var ruleName in results.formattedResults.ruleResults){
ruleArray.push(results.formattedResults.ruleResults[ruleName].localizedRuleName);
}
return ruleArray;
}
fiddle: https://jsfiddle.net/fo9h56gh/
Hope this helps.
you're probably getting a javascript error since counter is not defined. you can try this:
function ruleList(results) {
var ruleArray = [];
var counter = 0;
for(var ruleName in results.formattedResults.ruleResults){
ruleArray[counter] = results.formattedResults.ruleResults[ruleName].localizedRuleName;
counter++;
}
return ruleArray;
}

Categories

Resources