Merged array search functionality is not working - javascript

I'm having two data arrays which are coming from API and sample arrays would be like this
Array 1
[
{userId: 1
description: "Student"
imagePath: "test.png"
status: 1
}]
Array 2
[
{id: 85
accountName: "Rahul"
accountNumber: "11145678"
}
]
In my reactnative app view there's search bar and user should be able to search from these two arrays. So I merged these two arrays into one using
this.searchArray =this.filterArray[0].concat(this.filterArray[1])
So, my searchArray is a single array with Array1 and Array2 data. sample below
[
{userId: 1
description: "Student"
imagePath: "test.png"
status: 1
},
{id: 85
accountName: "Rahul"
accountNumber: "11145678"
}]
My search function is below (I need to search from account number or description)
//Search Filter
searchFilter =searchText=>{
const searchTextData = searchText.toUpperCase();
const userSearch = this.searchArray.filter(item => {
const itemData = `${item.description && item.description.toUpperCase()} ${item. accountName && item.accountName.toUpperCase()}`;
return itemData.indexOf(searchTextData) > -1;
});
}
The search functionality is not working with accountName. It's not getting any results. But if I remove ${item. accountName && item.accountName.toUpperCase()} , then it's working showing data with description. But I need to filter from both

In your array one object can have description or accountNumber so do a check if that exists include it in the itemData variable.
Try doing this
searchFilter =searchText=>{
const searchTextData = searchText.toUpperCase();
const userSearch = this.searchArray.filter(item => {
const itemData = `${item.hasOwnProperty('description'))?item.description.toUpperCase():''} ${item.hasOwnProperty('accountNumber')?item.accountNumber:''}`;
return itemData.indexOf(searchTextData) > -1;
});
}

First merge the two objects into one:
Object.keys(arr2[0]).forEach(key => {
arr1[0][key] = arr2[0][key]
})
Then create the search function:
function searchObject(obj, value){
return Object.keys(obj).some(key => {
return obj[key] === value
})
}
let arr1=[{userId:1,description:"Student",imagePath:"test.png",status:1}],arr2=[{id:85,accountName:"Rahul",accountNumber:"11145678"}];
Object.keys(arr2[0]).forEach(key => {
arr1[0][key] = arr2[0][key]
})
function searchObject(obj, prop, value){
return obj[prop] === value
}
console.log(searchObject(arr1[0], "accountName", "asdf"))
console.log(searchObject(arr1[0], "accountName", "Rahul"))

Related

Grouping Array element using two properties

I am attempting to group an array elements ( containing orders details ).
here is my array structure :
[{"id":"myid","base":{"brands":["KI", "SA"],"country":"BG","status":"new"}},{"id":"DEC-00500331","base":{"brands":["DEC"],"country":"UK","status":"new"},"psp":{"name":"adyen","status":"paid"}}]
An order is related to a country website, and can contain one or more brands. for example in one order I can have and item from brand1 and an item from brand2.
I need to group these orders, by country and brand so I can have a consolidated array or object.
I can group by country easily :
let groupedDataByCountryAndBrand = _.groupBy(orders.value, 'base.country')
Object.keys(groupedDataByCountryAndBrand).forEach(key => {
table.push(
{
country : key, //to be reviewd : for the two brands or more in one order
new : groupedDataByCountryAndBrand[key].filter( order => (order.base.status === SFCC_STATUS.new
|| SFCC_STATUS.open
|| SFCC_STATUS.completed )).length
})
})
Here is the result :
Unfortunatly this is not working for me. I need to group the orders by country and brand so that I can count the newly created orders for each brand by country.
Result I am expecting is something like this :
{
"country" : "FR",
"brand": "adidas",
"pending": 4
"new" : 3,
"an other status": 5
}
Do you have any idea how I can achieve this ?
I am using lodash with vue component.
Thanks.
Here is what you are looking for, without using of any additional libraries:
const data = [{"id":"myid","base":{"orderNumber":"0500332","marketPlaceOrderCode":"","creationDate":"2022-06-14T10:49:10Z","source":"sfcc","brands":["KI", "SA"],"country":"BG","status":"new","totalEuro":12,"currency":"BGN","units":1,"coupons":null,"shipping":{"id":"BG01","name":"Speedy COD","status":"not_shipped"}},"psp":{"name":"payu","method":null,"status":null},"tms":null},{"id":"DEC-00500331","base":{"orderNumber":"id2","marketPlaceOrderCode":"","creationDate":"2022-06-14T10:41:29Z","source":"sfcc","brands":["DEC"],"country":"UK","status":"new","totalEuro":57,"currency":"GBP","units":1,"coupons":null,"shipping":{"id":"ECA_DPD_ST","name":"Standard shipping","status":"not_shipped"}},"psp":{"name":"adyen","method":null,"status":"paid"},"tms":null}];
const rawResult = normalizeData(data);
console.log(makeItReadable(rawResult));
function normalizeData(data) {
const result = {};
data.forEach((order) => {
const orderData = order.base;
// add country to result (if not exists)
if (!result[orderData.country]) {
result[orderData.country] = {};
}
orderData.brands.forEach((brand) => {
// add brand to exact country (if not exists)
if (!result[orderData.country][brand]) {
result[orderData.country][brand] = {};
}
// add status to exact brand and country (if not exists)
if (!result[orderData.country][brand][orderData.status]) {
result[orderData.country][brand][orderData.status] = 0;
}
// increment status count
++result[orderData.country][brand][orderData.status];
});
});
return result;
}
function makeItReadable(rawData) {
const readableResult = [];
Object.keys(rawData).map((country) => {
Object.keys(rawData[country]).map((brand) => {
readableResult.push({country, brand, ...rawData[country][brand]});
});
});
return readableResult;
}
This code will give you the following result:
[
{ country: 'BG', brand: 'KI', new: 1 },
{ country: 'BG', brand: 'SA', new: 1 },
{ country: 'UK', brand: 'DEC', new: 1 }
]

What is the most efficient functional way for refactoring forEach loop?

I have a method which accepts items and available items from props. While iteration over an array I should filter items by two conditions inside the forEach loop. The first condition is passed item if item id doesn't exist or item id equal 1. The second one should return item and filter 'description' field, otherwise, we push our items into 'nextAvailableItems' array. What is the most efficient functional way for replacing the forEach loop in this situation?
Items structure:
[{
id: 23740416,
display_name: "test",
date_from: "1970-12-31"
}]
Available items structure:
[{
id: 23740416,
display_name: "test",
description: "Text"
}]
Expected output:
[{
id: 23740416,
display_name: "test"
}]
Current code:
buildAvailableItems() {
const { items, availableItems } = this.props
const nextAvailableItems = [...availableItems]
items.forEach(item => {
if (!item.id || item.id === -1) {
return
}
const availableItem = availableItems.find(availableItem => availableItem.id === item.id)
if (availableItem) {
const { id, display_name } = availableItem
return { id, display_name }
}
const { id, display_name } = item
nextAvailableItems.push({ id, display_name })
})
return nextAvailableItems
}
buildAvailableItems() {
const { items, availableItems } = this.props
const itemIds = items.reduce((c, i) => (c[i.id] = true, c), {})
const nextAvailableItems = availableItems
.filter(a => itemIds[a.id])
.map(a => ({ id: a.id, display_name: a.display_name }))
return [...availableItems, ...nextAvailableItems]
}
First, I would turn items into an ID lookup. Then filter your availableItems using that lookup. Then do the array merge last.

Filter array based on array of filters in Javascript

I have an array of users and also an array of filters.
I need to filter users based on the array of filters but when I do it will filter on one array but not the others
My filters object looks like this:
filters: {
levels: [],
locations: ['Laois'],
subjects: ['Art']
}
My users look like this:
const users = [
{
email: 'example1#gmail.com',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
{
email: 'example2#gmail.com',
levels: ['Higher', 'Ordinary'],
location: 'Laois',
subjects: ['English', 'German']
}
]
Based on the filter above, once filtered the users should only be one because it contains 'Art' and 'Laois':
[{
email: 'example1#gmail.com',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
]
But I am still getting the two users:
EDIT
My Code:
applyFilter = (visable) => {
let { filters, users } = this.state;
const { subjects, locations, levels } = filters;
let filteredUsers = [];
const filteredData = users.filter((user) =>
user.subjects.some(subject => subjects.includes(subject)) ||
locations.some(location => location === user.location) ||
user.levels.some(level => levels.includes(level))
);
console.log(filteredData)
if (!subjects.length && !locations.length && !levels.length) {
filteredUsers = users;
} else {
filteredUsers = filteredData;
}
this.setState({
filterModalVisible: visable,
filteredResults: filteredUsers.length >= 0 ? filteredUsers : [],
});
}
You can do this using filter and every methods by checking if every element from the filters value exist in the user value with the same key.
const filters = {"levels":[],"locations":["Laois"],"subjects":["Art"]}
const users = [{"email":"example1#gmail.com","levels":["Ordinary"],"locations":"Laois","subjects":["Art","German"]},{"email":"example2#gmail.com","levels":["Higher","Ordinary"],"locations":"Laois","subjects":["English","German"]}]
const res = users.filter(user => {
return Object.entries(filters)
.every(([key, value]) => {
if (Array.isArray(value)) {
return value.every(filter => {
return user[key] && user[key].includes(filter)
})
} else {
return user[key] == value
}
})
})
console.log(res)
You can try with filter()
const filters = {
levels: [],
locations: ['Laois'],
subjects: ['Art']
}
const users = [
{
email: 'example1#gmail.com',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
{
email: 'example2#gmail.com',
levels: ['Higher', 'Ordinary'],
location: 'Laois',
subjects: ['English', 'German']
}
]
var res = users.filter(info => info.location==filters.locations[0] && info.subjects.includes(filters.subjects[0]));
console.log(res);
You can have a generic solution for any filter key by using Array.filter, Array.some and Array.includes
Use filter to validate each entry against all the filter conditions
If an filter condition has an empty list, continue to check for next condition
For locations, as the filter key is different from the key in object, add a specific check for that where we check for location to be included in the locations array
For other fields, check for existence of atleast 1 entry in array that exists in filter value. If there exists a value, continue to check for next condition.
After condition check, confirm if the entry is valid, if not break the loop and return false
let filters = {levels: [],locations: ['Laois'],subjects: ['Art']};
let users = [{email: 'example1#gmail.com',levels: ['Ordinary'],location: 'Laois',subjects: ['Art', 'German']},{email: 'example2#gmail.com',levels: ['Higher', 'Ordinary'],location: 'Laois',subjects: ['English', 'German']}];
users = users.filter(v => {
let response = true;
for (let filter in filters) {
if(!filters[filter].length) continue;
if(filter === "locations") {
response = response && filters.locations.includes(v.location)
} else response = response && v[filter].some(f => filters[filter].includes(f));
if(!response) break;
}
return response;
});
console.log(users);
Using filter inside filter
const filters = {
levels: [],
locations: ['Laois'],
subjects: ['Art']
}
const users = [
{
email: 'example1#gmail.com',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
{
email: 'example2#gmail.com',
levels: ['Higher', 'Ordinary'],
location: 'Laois',
subjects: ['English', 'German']
}
]
console.log(users.filter((e) => {
var arr = e.subjects.filter((x) => filters.subjects.includes(x))
if (arr.length > 0 && filters.locations.includes(e.location))
return e
}))
You need to use && instead of || if you want to match all conditions
As per your requirements, you need all of them to match if filter array is empty, so you can just bypass the check for that case
applyFilter = (visable) => {
let { filters, users } = this.state;
const { subjects, locations, levels } = filters;
const filteredResults = users.filter((user) =>
(!subjects.length || user.subjects.some(subject => subjects.includes(subject))) &&
(!locations.length || locations.some(location => location === user.location)) &&
(!levels.length || user.levels.some(level => levels.includes(level)))
);
this.setState({
filterModalVisible: visable,
filteredResults
});
}

Matching two Observable Data Objects with combineLatest

I have two observable arrays: First array object observable
array1= Observable.of({
data: [
{
name: 'test',
lastname: 'last'
},
{
name: 'test1',
lastname: 'last1'
}
]
}).map(res => {
return res.data;
});
// Second Observable:
array2 = Observable.of('test1');
Expected Result from the above two array is that wherever firstname is matching with array2 value, get the lastname from that object.
//Expected Result:
object3=Observable.of('last')
It looks like you're using RxJS 5.4 so you could do it like this for example:
Observable.combineLatest(array1, array2)
.map(([users, name]) => {
const user = users.find(u => u.name === name);
return user ? user.lastname : null;
})
.subscribe(console.log);
See live demo: https://stackblitz.com/edit/rxjs5-4nyq3s?file=index.ts

Group the same `category` objects [duplicate]

This question already has answers here:
Group array items using object
(19 answers)
Closed 6 years ago.
I'm trying to group the raw data from:
items:
[
{
category: "blog",
id : "586ba9f3a36b129f1336ed38",
content : "foo, bar!"
},
{
category: "blog",
id : "586ba9f3a36b129f1336ed3c",
content : "hello, world!"
},
{
category: "music",
id : "586ba9a6dfjb129f1332ldab",
content : "wow, shamwow!"
},
]
to
[
{
category: "blog",
items:
[
{
id : "586ba9f3a36b129f1336ed38",
content : "foo, bar!"
},
{
id : "586ba9f3a36b129f1336ed3c",
content : "hello, world!"
},
]
},
{
category: "music",
items:
[
{
id : "586ba9a6dfjb129f1332ldab",
content : "wow, shamwow!"
}
]
}
]
The format like this helps me to print the same category data together in the frontend.
The content of the category field is dynamically, so I'm not sure how do I store it to a temporary object and sort them, any thoughts?
(I can't think a better title for the question, please edit if you got a better title.)
You can do it using Array#reduce in one pass:
var items = [{"category":"blog","id":"586ba9f3a36b129f1336ed38","content":"foo, bar!"},{"category":"blog","id":"586ba9f3a36b129f1336ed3c","content":"hello, world!"},{"category":"music","id":"586ba9a6dfjb129f1332ldab","content":"wow, shamwow!"}];
var result = items.reduce(function(r, item) {
var current = r.hash[item.category];
if(!current) {
current = r.hash[item.category] = {
category: item.category,
items: []
};
r.arr.push(current);
}
current.items.push({
id: item.id,
content: item.content
});
return r;
}, { hash: {}, arr: [] }).arr;
console.log(result);
Or the ES6 way using Map:
const items = [{"category":"blog","id":"586ba9f3a36b129f1336ed38","content":"foo, bar!"},{"category":"blog","id":"586ba9f3a36b129f1336ed3c","content":"hello, world!"},{"category":"music","id":"586ba9a6dfjb129f1332ldab","content":"wow, shamwow!"}];
const result = [...items.reduce((r, { category, id, content }) => {
r.has(category) || r.set(category, {
category,
items: []
});
r.get(category).items.push({ id, content });
return r;
}, new Map).values()];
console.log(result);
Personally, without any helper libraries, I'd just do this
var step1 = items.reduce((result, {category, id, content}) => {
result[category] = result[category] || [];
result[category].push({id, content});
return result;
}, {});
var result = Object.keys(step1).map(category => ({category, items: step1[category]}));
Which babel converts to
var step1 = items.reduce(function (result, _ref) {
var category = _ref.category,
id = _ref.id,
content = _ref.content;
result[category] = result[category] || [];
result[category].push({ id: id, content: content });
return result;
}, {});
var result = Object.keys(step1).map(function (category) {
return { category: category, items: step1[category] };
});
So I just solved the question with the following code (jsfiddle):
// Items
// var items = []
// Create an empty object, used to store the different categories.
var temporaryObject = {}
// Scan for each of the objects in the `items` array.
items.forEach((item) =>
{
// Create a category in the teporary object if the category
// hasn't been created.
if(typeof temporaryObject[item.category] === "undefined")
temporaryObject[item.category] = []
// Push the item to the its category of the `temporaryObject`.
temporaryObject[item.category].push({
id : item.id,
content: item.content
})
})
// Create a empty array used to stores the sorted, grouped items.
var newItems = []
// Scan for each of the category in the `temporaryObject`
for(var category in temporaryObject)
{
// Push the new category in the `newItems` array.
newItems.push({
category: category,
items : []
})
// Get the last category index of the `newItems` array,
// so we can push the related data to the related category.
var lastItem = newItems.length - 1
// Scan for the related category in the `temporaryObject` object.
temporaryObject[category].forEach((item) =>
{
// Push the related data to the related category of the `newItems` array.
newItems[lastItem].items.push(item)
})
}
// Prints the sorted, grouped result.
console.log(newItems)

Categories

Resources