Filter data in NodeJS - javascript

I have a json array where it contains an objects having name and rating fields.I want to filter that array where rating is 5.It might be the easy one find but I got stuck.
Below is my json object.
let products = [
{
"name" : "product 1",
"rating" : 5
},
{
"name" : "product 2",
"rating" : 4
},
{
"name" : "product 3",
"rating" : 5
},
{
"name" : "product 4",
"rating" : 2
}]
Here I am using filter functionality but unable to get How can I use it properly.
This is the function I have written but its not working.
const prod = (products) => {
products.filter((proct) => {
if(proct === 5){
console.log(proct.name);
}
});
}
prod(products);
Someone let me know what I am doing wrong.

filter function must return a boolean as result
Function is a predicate, to test each element of the array. Return a value that coerces to true to keep the element, or to false otherwise.
Array.prototype.filter
let products = [{ "name": "product 1", "rating": 5 }, { "name": "product 2", "rating": 4 }, { "name": "product 3", "rating": 5 }, { "name": "product 4", "rating": 2 } ]
products = products.filter(({rating}) => rating === 5)
console.log(products)
Each item in your array is an object, and I guess you are looking for rating===5.
Your function should be:
let products = [{ "name": "product 1", "rating": 5 }, { "name": "product 2", "rating": 4 }, { "name": "product 3", "rating": 5 }, { "name": "product 4", "rating": 2 } ]
const prod = (products) => {
products.filter((proct) => {
if (proct.rating === 5) {
console.log(proct.name);
return true;
}
return false
});
}
prod(products)
Getting just name key:
Take a look at map function which create a new array from old array:
.map(({name}) => name)
Full code:
let products = [{ "name": "product 1", "rating": 5 }, { "name": "product 2", "rating": 4 }, { "name": "product 3", "rating": 5 }, { "name": "product 4", "rating": 2 } ]
products = products.filter(({rating}) => rating === 5).map(({name}) => name)
console.log(products)

Your code is not checking the property. But the object itself. Use the . operator to check the specific property:
let products = [
{
"name" : "product 1",
"rating" : 5
},
{
"name" : "product 2",
"rating" : 4
},
{
"name" : "product 3",
"rating" : 5
},
{
"name" : "product 4",
"rating" : 2
}]
const prod = (products) => {
products.filter((proct) => {
if(proct.rating === 5){
console.log(proct.name);
}
});
}
prod(products);

Your condition is comparing proct, an object, to the value 5. You probably forgot to access the rating property of proct:
products.filter((proct) => {
if(proct.rating === 5){
console.log(proct.name);
}
});
However, you are using filter wrong. Filter is a method whose entire point is to get all the elements in the array that answer a condition and return them, and not just iterate over an array and execute code (that's what forEach is for). A more correct code would be:
const filteredProducts = products.filter((proct) => proct.rating === 5);
console.log(filteredProducts); // [{ name: "product 1", rating: 5 }, { name: "product 3", rating: 5 }]
filteredProducts.forEach((proct) => console.log(proct.name));
This solution first retrieves all the products whose rating is 5 and then iterates over each of them to print their name.

Related

Recursively Find and Add Them as an Array

I have this kind of table (or data structure)
There is parentIdeaId that refers to the id in ideas table itself.
Here's my unstructured data (please bear in mind this is the existing data in the database, not data that is already as it is so I have to query this first under some condition)
[{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
},{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
},{
"id": "4",
"title": "Title 4",
"parentIdeaId": null
}]
I also made a function to find the data (I'm using Prisma in my real code)
function find({ id }) {
return prisma.idea.findUnique({
where: {
id
}
});
}
And a function to find the children
function responseIdeas({ parentIdeaId }) {
return prisma.idea.findMany({
where: {
parentIdeaId
}
});
}
I want the data to be filtered only linked data (by their parentIdeaId) so if I query the id "1" the result would be
[{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
}{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
}]
The id: "4" isn't inserted because it's not related by its parent
Here's what I made:
const data = [
{
id: "1",
title: "Title 1",
parentIdeaId: null
},
{
id: "2",
title: "Title 2",
parentIdeaId: 1
},
{
id: "3",
title: "Title 3",
parentIdeaId: 2
},
{
id: "4",
title: "Title 4",
parentIdeaId: null
}
];
function find({ id }) {
return data.find(e => e.id === id);
}
function responseIdeas({ parentIdeaId }) {
return data.filter(e => e.parentIdeaId == parentIdeaId);
}
async function detail({ id }) {
const findChildren = async ({ id }) => {
const idea = await find({ id });
const responses = await responseIdeas({ parentIdeaId: id });
if (responses.length !== 0) {
const resolveResponses = await Promise.all(
responses.map(async ({ id }) => findChildren({ id }))
);
return [idea, ...resolveResponses];
}
return { ...idea };
};
return findChildren({ id });
}
async function run() {
const result = await detail({ id: "1" });
console.dir(result, { depth: null });
}
run();
But it ended up being like this
[
{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},
[
{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
},
{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
}
]
]
Where did I mess up? Thanks
findChildren potentially returns an array of arrays due to the fact that your returning Promise.all() -> which is a array of promises and some of those promises can be arrays.
So you can use concat to merge the result into the main array e.g like this https://codesandbox.io/s/quizzical-sun-c4khx?file=/src/index.js

Merge two arrays and compare by ID add new Property

Hopefully someone can help me out here.
I am building an angular app with SQLite database which stores existing values. I need to compare these values from a json array received over http.
They should be matched by code, I want to compare the existing values with the update values add the property "active" = 1 otherwise active = 0 .
I tried a double foreach loop below, but I guess what's happening is the index is off so the results are not accurate in my actual application.
I have lodash available if there is some way to do this using that.
Any help would be much appreciated.
How can I get the following output
/*epected output
[{
"name": "Person 1"
"code": '001',
"active": '1'
},
{
"name": "Person 2"
"code": '002',
"active": '1'
},
{
"name": "Person 3"
"code": '003',
"active": '0' // note active 0 since doesnt exist in exsting
}
]*/
and what I tried along with 500 other things.
const existing = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
];
const update = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
{
"name": "Person 3",
"code": '003',
},
];
existing.forEach(element => {
update.forEach(test => {
if (element.code === test.code) {
element.avtive = true;
} else {
element.avtive = false;
}
});
return element;
});
console.log(existing);
/*epected output
[{
"name": "Person 1"
"code": '001',
"active": '1'
},
{
"name": "Person 2"
"code": '002',
"active": '1'
},
{
"name": "Person 3"
"code": '003',
"active": '0' // note active 0 since doesnt exist in exsting
}
]*/
Here is what should work for you. All existing code are extracted and then, for each updated value it is checked whether code exists in existingCodes array.
const existingCodes = existing.map((e) => e.code);
const result = updated.map((e) => ({
...e,
active: existingCodes.includes(e.code) ? '1' : '0'
});
If includes doesn't work for you on IE, you can replace this line existingCodes.includes(e.code) with existingCodes.filter((code) => code === e.code).length.
I like #radovix answer above, which worked for me, I came up with something slightly more long-winded, but which gives the same end result, but also separate lists of active and inactive:
let active = update.filter(item =>{
return existing.find(exist=> exist.code == item.code);
});
let inactive = update.filter(item =>{
return !existing.find(exist=> exist.code == item.code);
});
active = active.map(item=>({...item, active: '1'}));
inactive= inactive.map(item=>({...item, active: '0'}));
const merged = [...this.active, ...this.inactive];
You can see both ways working here: https://stackblitz.com/edit/angular-merge-arrays-update-property
You can use reduce, find and remove item from update array as
let result= existing.reduce((acc, item)=>{
let found = update.find(c => c.name == item.name);
if (found != undefined) {
const index = update.indexOf(found);
if (index > -1) {
update.splice(index, 1);
}
}
item.active = true;
acc.push(item);
return acc;
},[]);
update.map(c=> c.active = false);
//console.log(update)
result = result.concat(update);
console.log(result);
const existing = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
];
const update = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
{
"name": "Person 3",
"code": '003',
},
];
let result= existing.reduce((acc, item)=>{
let found = update.find(c => c.name == item.name);
if (found != undefined) {
const index = update.indexOf(found);
if (index > -1) {
update.splice(index, 1);
}
}
item.active = true;
acc.push(item);
return acc;
},[]);
update.map(c=> c.active = false);
//console.log(update)
result = result.concat(update);
console.log(result);

Parsing JSON and forming a customized array

What I have,
{
"rowId": "1",
"product_name": [
"Product 1",
"Product 2",
"Product 3",
"Product 4",
"Product 5"
],
"product_tag": [
"1112231",
"1112232",
"1112233",
"1112234",
"1112235"
],
"version_id": [
"1.0",
"2.0",
"1.5",
"3.0",
"2.5"
]
}
How I would like it to get transformed. (i.e, taking every element from each array in the JSON given above and forming a new array like below).
{
[
"Product 1",
"1112231",
"1.0"
],
[
"Product 2",
"1112232",
"2.0"
],
[
"Product 3",
"1112233",
"1.5"
],
[
"Product 4",
"1112234",
"3.0"
],
[
"Product 5",
"1112235",
"2.5"
]
}
What I've tried,
I've tried using the flatMap function of javascript (given below) but with no luck. (Note: Here testData refers to the JSON data pasted above)
[testData.product_name, testData.product_tag, testData.version_id].flatMap((i, index) => i[index]);
which returns only one record like this (where I need to get 5 in my case),
["Product 1","1112232","1.5"]
Can someone help?
You could use Array.from like this:
const input={"rowId":"1","product_name":["Product 1","Product 2","Product 3","Product 4","Product 5"],"product_tag":["1112231","1112232","1112233","1112234","1112235"],"version_id":["1.0","2.0","1.5","3.0","2.5"]}
const { product_name, product_tag, version_id } = input;
const output =
Array.from(input.product_name, (name, i) => ([ name, product_tag[i], version_id[i] ]))
console.log(output)
If you have unequal number of items in each array, you could get the biggest array's length to create the output
// or Math.min if you don't want undefined items
const length = Math.max(product_name.length, product_tag.length, version_id.length)
const output =
Array.from({ length }, (_, i) => ([ product_name[i] , product_tag[i], version_id[i] ]))
You could reduce the value/arrays and assign the items to the array with the same index.
var object = { rowId: "1", product_name: ["Product 1", "Product 2", "Product 3", "Product 4", "Product 5"], product_tag: ["1112231", "1112232", "1112233", "1112234", "1112235"], version_id: ["1.0", "2.0", "1.5", "3.0", "2.5"] },
result = Object.values(object).reduce((r, a) => {
Array.isArray(a) && a.forEach((v, i) => (r[i] = r[i] || []).push(v));
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use construct an array including the product_name, product_tag and version_id in the order you prefer. This is to make sure that the order is right. Use reduce to loop thru the array. Use forEach to loop in the inner array.
let data = {"rowId":"1","product_name":["Product 1","Product 2","Product 3","Product 4","Product 5"],"product_tag":["1112231","1112232","1112233","1112234","1112235"],"version_id":["1.0","2.0","1.5","3.0","2.5"]}
let result = [data.product_name, data.product_tag, data.version_id].reduce((c, v) => {
v.forEach((e, i) => {
c[i] = c[i] || [];
c[i].push(e);
});
return c;
}, []);
console.log(result);
let arr = obj.product_name.map((it,index)=>[it,obj.product_tag[index],obj.version_id[index]])
you can use do it like this if you want
const ar= {
"rowId": "1",
"product_name": [
"Product 1",
"Product 2",
"Product 3",
"Product 4",
"Product 5"
],
"product_tag": [
"1112231",
"1112232",
"1112233",
"1112234",
"1112235"
],
"version_id": [
"1.0",
"2.0",
"1.5",
"3.0",
"2.5"
]
};
let newAr = {};
for(var i = 0;i < ar.product_name.length;i++){
newAr[i]= [ar.product_name[i],ar.product_tag[i],ar.version_id[i]];
}

How to find number of items which contains specific string using js filter method

I would like to find number of items which has specific text using js filter method.
var num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
num is an object;
Now, i want to find number of categories which has text 'cat'. So i want the result 2. How to get that using filter method.
here's how you can do it
var num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
console.log( num.filter(i => i.category.indexOf("cat") === 0).length )
num is an object;
True, but specifically it's an array object.
You could use filter for this, but reduce would be the more appropriate option if you don't want the array of matching results:
var result = num.reduce(function(sum, entry) => sum + (entry.category.includes("cat") ? 1 : 0), 0);
Live Example:
var num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
var result = num.reduce(function(sum, entry) {
return sum + (entry.category.includes("cat") ? 1 : 0);
}, 0);
console.log(result);
Or with ES2015+:
const num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
const result = num.reduce((sum, entry) => sum + (entry.category.includes("cat") ? 1 : 0), 0);
console.log(result);
Or of course, a simple for loop.
This is fairly simple. In ES6 the solution would be this:
const countOfCats = num.filter(entry => entry.category.match('cat')).length;
Another way could be:
const countOfCats = num.filter(entry => entry.contains("cat")).length;

Use map and filter to handle items with same value

In the example below, I have an array of objects which contain some basic information about films - a film name and a personal rating.
Then i'm returning the duplicate values (using map and filter) to return new arrays and I can then count the number of items in that new array.
let films = [{
"name": "film 1",
"rating": "5",
}, {
"name": "film 2",
"rating": "1",
}, {
"name": "film 3",
"rating": "2",
}, {
"name": "film 4",
"rating": "2",
}, {
"name": "film 5",
"rating": "5",
}, {
"name": "film 6",
"rating": "4",
}];
let ratingsArray = films.map((element, i) => {
return element.rating;
})
let arr0 = ratingsArray.filter((rating) => {
return rating == 0;
})
let arr1 = ratingsArray.filter((rating) => {
return rating == 1;
})
let arr2 = ratingsArray.filter((rating) => {
return rating == 2;
})
let arr3 = ratingsArray.filter((rating) => {
return rating == 3;
})
let arr4 = ratingsArray.filter((rating) => {
return rating == 4;
})
let arr5 = ratingsArray.filter((rating) => {
return rating == 5;
});
console.log(arr0);
console.log(arr1);
console.log(arr2);
console.log(arr3);
console.log(arr4);
console.log(arr5);
This does actually work but it seems a very repetitive way of writing this code.
Can anyone please suggest a better that I could be doing this?
You could take an object and group the objects by rating.
var films = [{ name: "film 1", rating: "5", }, { name: "film 2", rating: "1", }, { name: "film 3", rating: "2", }, { name: "film 4", rating: "2", }, { name: "film 5", rating: "5", }, { name: "film 6", rating: "4", }],
ratings = Object.create(null);
films.forEach(o => (ratings[o.rating] = ratings[o.rating] || []).push(o));
console.log(ratings);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can write a function that you can use as the callback in filter. It works similarly to how lodash's pluck method worked. pluck accepts a property key, and value and returns a closure that's used as the callback function when filter iterates over the elements in the array.
let films = [
{ "name": "film 1", "rating": "5" },
{ "name": "film 2", "rating": "1" },
{ "name": "film 3", "rating": "2" },
{ "name": "film 4", "rating": "2" },
{ "name": "film 5", "rating": "5" },
{ "name": "film 6", "rating": "4" }
];
function pluck(key, value) {
return function (el) {
return el[key] === value;
}
}
const rating4 = films.filter(pluck('rating', '2'));
console.log(rating4);
You can then use this as you see fit, whether you want to loop over a set of ratings and store that information in an object, for example, but this is completely up to you. And you can use this function not just on this data set, but all sets where you need to pull out this kind of data.
let characters = [{
"name": "Batman",
"age": 62
}, {
"name": "Supergirl",
"age": 27
}, {
"name": "Tarzan",
"age": 102
}];
function pluck(key, value) {
return function (el) {
return el[key] === value;
}
}
const tarzan = characters.filter(pluck('age', 102));
console.log(tarzan);
One thing tho: you might benefit from having the ratings as integers rather than strings. One thing to consider moving forward.
You need to grouping the films by rating you can do using a object and arrays to store. See the example bellow:
let films = [{
"name": "film 1",
"rating": "5",
}, {
"name": "film 2",
"rating": "1",
}, {
"name": "film 3",
"rating": "2",
}, {
"name": "film 4",
"rating": "2",
}, {
"name": "film 5",
"rating": "5",
}, {
"name": "film 6",
"rating": "4",
}];
var filmsByRating = {};
//group films by rating
films.forEach((film) => {
if(!filmsByRating[film.rating])
filmsByRating[film.rating] = [];
filmsByRating[film.rating].push(film);
});
//print ratings and films
for(var i in filmsByRating){
console.log("Rating:", i);
console.log(filmsByRating[i]);
}
I'm going to combine concepts from other answers and suggestions therein, and generate an Array, using reduce. Some advantages of putting the ratings into an Array instead of an Object include that you will then be able to perform useful Array methods such as reverse or (custom) sort e.g. maybe you want to sort by the rating that has the most films associated with it.
var films = [
{ name: "film 1", rating: "5", },
{ name: "film 2", rating: "1", },
{ name: "film 3", rating: "2", },
{ name: "film 4", rating: "2", },
{ name: "film 5", rating: "5", },
{ name: "film 6", rating: "4", }
];
var ratings = films.reduce(function(result, film) {
var rating = parseInt(film.rating, 10);
var ratedFilms = result[rating] || [];
ratedFilms.push(film);
result[rating] = ratedFilms;
return result;
}, []);
ratings.forEach(function(rating, i) {
console.log(i + ": " + JSON.stringify(rating));
});
RESULT:
1: [{"name":"film 2","rating":"1"}]
2: [{"name":"film 3","rating":"2"},{"name":"film 4","rating":"2"}]
4: [{"name":"film 6","rating":"4"}]
5: [{"name":"film 1","rating":"5"},{"name":"film 5","rating":"5"}]

Categories