I am trying to search an array for query string on a json object. The returned fields are an array of filtered results. Currently, the list is returning the name field but not the number field.
computed: {
search: function () {
let self = this
let filtered = []
filtered = self.jcontacts.filter(function(contact){
return contact.firstname.toLowerCase().indexOf(self.query.toLowerCase())>=0 ||
contact.lastname.toLowerCase().indexOf(self.query.toLowerCase())>=0;
contact.email.toLowerCase().indexOf(self.query.toLowerCase()) >=0 ||
contact.phonenumber.toLowerCase().indexOf(self.query.toLowerCase()) >=0;
}
);
return this.contacts = filtered
}
},
}
The filtered method in the search method is not showing the number. An example of the json is below:
[
{
"id": 1,
"phoneNumber": [
"3908902"
],
"email": [
"jamie#fox.com"
],
"firstname": "Jamie",
"lastname": "Fox"
}]
Beware of case phoneNumber != phonenumber
phoneNumber is stored as array not string, so you cant look for it like that (use .includes() function for example)
For code formatting consider to store self.query.toLowerCase() as variable or another computed property
It is a typo. Check out field phoneNumber is filtered as phonenumber.
It is an array so you can do it as,
contact.phoneNumber.forEach( number => {
if(number.toLowerCase().indexOf(self.query.toLowerCase()) >=0)
return true;
});
I think similarly you can write it down for email as well because it is also an array.
Related
I have some data (json) that looks like this:
[
{
"name": "Enterprise Networking",
"technology": "Networking"
},
{
"name": "Enterprise Networking",
"technology": "Networking"
},
{
"name": "Wireless Insights",
"technology": "Mobility and Wireless"
},
{
"name": "Mobility Insights",
"technology": "Mobility and Wireless"
},
{
"name": "Lock it down",
"technology": "Security"
},
{
"name": "Collaboration",
"technology": "Security"
}
]
I am trying to find matches based on an array of filtering options for one field named 'technology' in this example. For example, my filtering criteria will be ["Networking", "Security"]. I would expect to return all objects that have 'Networking' and 'Security' as their technology, excluding 'Mobility and Wireless' in this example.
I have figured out how to do it with just one filter criteria using:
result = learningMapsDataObj.filter(el => el.Technology === filter3[0].value);
I've tried adding a method that will loop through the the filter array, but can't get it to work.
result = learningMapsDataObj.filter(el => el.Technology === myloopingArrCheckFunction(el.technology, filters3));
I know I'm close, but haven't had to dev in a while and my multidimensional brain isn't working.
Approaches
You can check if el.technology is included in your array of values to filter by:
const allowedTechnologies = ["Networking", "Security"];
learningMapsDataObj.filter(el => allowedTechnologies.includes(el.technology))
Alternatively, you can also check if el.technology is like some of the values to filter by:
const allowedTechnologies = ["Networking", "Security"];
learningMapsDataObj.filter(el => { // Linebreak (thus function body) for readability
return allowedTechnologies.some(allowedTech => allowedTech === el.technology);
})
Map to string array
It seems your filter is in a form similar to this:
const filter = [
{ value: "Networking" }.
{ value: "Security" }
];
But it would be easier to use if it was in the form as shown in my examples above. You can achieve that by mapping the filter elements to their values:
const filter = [
{ value: "Networking" }.
{ value: "Security" }
];
const filterValues = filter.map(el => el.value);
// Now you can use filterValues like allowedTechnologies
let result = learningMapsDataObj.filter(el => el.technology === "Networking" || el.technology === "Security" );
You can filter the array with an array of criterias like this
const filterCriteria= ["Networking", "Security"]
const filteredArray = learningMapsDataObj.filter((item) => filterCriteria.includes(item.technology));
if you want to set a variable for fields you want to filter, you can also do something like this
const filterField = 'technology'
const filterCriteria= ["Networking", "Security"]
const filteredArray = learningMapsDataObj.filter((item) => filterCriteria.includes(item[filterField]));
I have an array of objects and within those objects is another object which contains a particular property which I want to get the value from and store in a separate array.
How do I access and store the value from the name property from the data structure below:
pokemon:Object
abilities:Array[2]
0:Object
ability:Object
name:"blaze"
1:Object
ability:Object
name:"solar-power"
How would I return and display the values in the name property as a nice string like
blaze, solar-power ?
I tried doing something like this but I still get an array and I don't want to do a 3rd loop since that is not performant.
let pokemonAbilities = [];
let test = pokemon.abilities.map((poke) =>
Object.fromEntries(
Object.entries(poke).map(([a, b]) => [a, Object.values(b)[0]])
)
);
test.map((t) => pokemonAbilities.push(t.ability));
Sample Data:
"pokemon": {
"abilities": [
{
"ability": {
"name": "friend-guard",
"url": "https://pokeapi.co/api/v2/ability/132/"
},
"ability": {
"name": "Solar-flare",
"url": "https://pokeapi.co/api/v2/ability/132/"
}
}
]
}
Then I am doing a join on the returned array from above to get a formatted string.
It just seems like the multiple map() loops can be optimized but I am unsure how to make it more efficient.
Thank you.
There is no need for a loop within loop. Try this:
const pokemon = {
abilities: [{
ability: {
name: 'friend-guard',
url: 'https://pokeapi.co/api/v2/ability/132/'
},
}, {
ability: {
name: 'Solar-flare',
url: 'https://pokeapi.co/api/v2/ability/132/'
}
}]
};
const pokemonAbilities = pokemon.abilities.map(item => item.ability.name).join(', ');
console.log(pokemonAbilities);
I have a function that is using eval to convert a string with an expression to an object based on the parameter.
let indexType = ["Mac", "User", "Line", "Mask", "Ip", "Location"]
const filterIndex = (item) => {
filteredIndexSearch = []
eval(`search${item}`).forEach((e) => filteredIndexSearch.push(searchData[e.key]))
}
filterIndex(indexType[searchTotal.indexOf(Math.max(...searchTotal))])
searchData is an array that returns values based on the user input.
searchTotal is an array with the length of each search{item} array.
The filterIndex function takes the highest value from the searchData array and corresponds it to the indexType array, then use eval to convert the string to an object to pass the value to the filteredIndexSearch array.
What would be a better alternative to eval?
EDIT
To add more information on what this does:
searchData = [
[
{
key: 1,
data: "0123456789101"
},
{
key: 1,
data: "John Smith"
}
],
[
{
key: 2,
data: "0123456789102"
},
{
key: 2,
data: "Jane Smith"
},
]
]
const search = (data, key, container) => {
if (!data) data = "";
if (data.toLowerCase().includes(string)) {
container = container[container.length] = {
key: key,
data: data
}
}
}
const returnSearch = () => {
for (let i = 0; i < searchData.length; i++) {
search(searchData[i][0].data, searchData[i][0].key, searchMac)
search(searchData[i][1].data, searchData[i][1].key, searchUser)
}
}
returnSearch()
The data is incomplete, but hopefully conveys what I'm trying to do.
search will take the user input, and store the information in the corresponding array. If I input "Jo", it will return the searchUser array with only the "John Smith" value and all the other values with the same key. Inputting "102" returns the searchMac with the "0123456789102" value and all other values with the same key.
At the end of the day. I just want to convert search${parameter} to an object without using eval.
Move your global arrays into an object.
Somewhere it appears that you're defining the arrays, something like:
searchMac = [...];
searchUser = [...];
...
Instead of defining them as individual arrays, I'd define them as properties in an object:
searchIndices.Mac = [...];
searchIndices.User = [...];
...
Then, instead of using eval, your can replace your eval().forEach with searchIndices[item].forEach.
If the order of your search isn't important, your can instead loop through the keys of searchIndices:
Object.keys(searchIndices).forEach(item => {
searchIndices[item].forEach(...);
});
This ensures that if you ever add or drop an entry in searchIndices, you won't miss it or accidentally error out on an undefined search index.
Any time you have a situation with variables named x0, x1 etc, that should be a red flag to tell you you should be using an array instead. Variable names should never be semantically meaningful - that is code should never rely on the name of a variable to determine how the code behaves. Convert search0 etc into an array of search terms. Then use:
const filterIndex = (item) => search[item].map(i => searchData[i.key]);
filteredIndexSearch = filterIndex(indexType[searchTotal.indexOf(Math.max(...searchTotal))]);
(simplifying your code). Note that in your code, filteredIndexSearch is modified inside the arrow function. Better to have it return the result as above.
I am having a hard time filtering through an array of objects based on a value in a nested array of objects. I have a chat application where a component renders a list of chats that a user has. I want to be able to filter through the chats by name when a user types into an input element.
Here is an example of the array or initial state :
const chats= [
{
id: "1",
isGroupChat: true,
users: [
{
id: "123",
name: "Billy Bob",
verified: false
},
{
id: "456",
name: "Superman",
verified: true
}
]
},
{
id: "2",
isGroupChat: true,
users: [
{
id: "193",
name: "Johhny Dang",
verified: false
},
{
id: "496",
name: "Batman",
verified: true
}
]
}
];
I want to be able to search by the Users names, and if the name exists in one of the objects (chats) have the whole object returned.
Here is what I have tried with no results
const handleSearch = (e) => {
const filtered = chats.map((chat) =>
chat.users.filter((user) => user.name.includes(e.target.value))
);
console.log(filtered);
// prints an empty array on every key press
};
const handleSearch = (e) => {
const filtered = chats.filter((chat) =>
chat.users.filter((user) => user.name.includes(e.target.value))
);
console.log(filtered);
// prints both objects (chats) on every keypress
};
Expected Results
If the input value is "bat" I would expect the chat with Id of 2 to be returned
[{
id: "2",
isGroupChat: true,
users: [
{
id: "193",
name: "Johhny Dang",
verified: false
},
{
id: "496",
name: "Batman",
verified: true
}
]
}]
The second approach seems a little closer to what you're trying to accomplish. There's two problems you may still need to tackle:
Is the search within the name case insensitive? If not, you're not handling that.
The function being used by a filter call needs to return a boolean value. Your outer filter is returning all results due to the inner filter returning the array itself and not a boolean expression. Javascript is converting it to a "truthy" result.
The following code should correct both of those issues:
const filtered = chats.filter((chat) => {
const searchValue = e.target.value.toLowerCase();
return chat.users.filter((user) => user.name.toLowerCase().includes(searchValue)).length > 0;
});
The toLowerCase() calls can be removed if you want case sensitivity. The .length > 0 verifies that the inner filter found at least one user with the substring and therefore returns the entire chat objects in the outer filter call.
If you want to get object id 2 when entering bat you should transform to lowercase
const handleSearch = (e) =>
chats.filter(chat =>
chat.users.filter(user => user.name.toLowerCase().includes(e.target.value)).length
);
try this it should work
const handleSearch2 = (e) => {
const filtered = chats.filter((chat) =>
chat.users.some((user) => user.name.includes(e))
);
console.log(filtered);
};
filter needs a predicate as argument, or, in other words, a function that returns a boolean; here some returns a boolean.
Using map as first iteration is wrong because map creates an array with the same number of elements of the array that's been applied to.
Going the easy route, you can do this.
It will loop first over all the chats and then in every chat it will check to see if the one of the users' username contains the username passed to the function. If so, the chat will be added to the filtered list.
Note, I am using toLowerCase() in order to make the search non case sensitive, you can remove it to make it case sensitive.
const handleSearch = (username) => {
var filtered = [];
chats.forEach((chat) => {
chat.users.forEach((user) => {
if (user.name.toLowerCase().includes(username.toLowerCase())) {
filtered.push(chat);
}
});
});
console.log(filtered);
return filtered;
}
handleSearch('bat');
I am trying to build a query builder which will allow me to filter the data based on the parameters entered by user. My Data Model is like so:
{
"_id": {
"$oid": "871287215784812"
},
"tags": [
"school",
"book",
"bag",
"headphone",
"appliance"
],
"consultingDays": 57,
"client": "someOne",
"subSector": "something",
"region": "UK",
"__v": 0
}
Currently my Query Builder looks like this:
app.post('/user/test',function(req, res) {
var query = {};
//QUERY NO.1 - This works perfectly
if (req.body.region){
query.region = req.body.region
console.log(query.region)
}
// QUERY NO.2 - This works perfectly
if (req.body.subSector){
query.subSector = req.body.subSector
}
Project.find(query, function(err, project){
if (err){
res.send(err);
}
console.log(project);
res.json(project);
});
});
My Question:
I want to create a query which will take input from user and parse the "tags" array and return the required JSON.
For example:
If the user requests an object which contains "school", "book", "bag" it will return the object as seen my data model above. But if the user requests an object with "school", "book", "ninja Warrior" it won't return any data as no object within the database contain all those 3 strings.
What I have tried:
I have tried the following
if (req.body.sol){
query.solutions = {"tags" : {$in: [req.body.sol]}}
}
OR
if (req.body.sol){
query.solutions = {$elemMatch:{tags: req.body.sol}}
}
OR
if (req.body.sol){
query.solutions = { tags: { $all: [req.body.sol]}}
}
The requests were sent like so and they returned an empty array:
Also the issue is that the user will get dropdown options. For example he/she might get 3 dropdown boxes. Each dropdown box will display all the five options in the tags array. The user will select a value for each dropdown box. And then filter the result. Because there might be an object within the database that contains "book", "bag", "shoes" within the tags array. The user can select any combination of those five keywords in the tags array
Does anyone know how I can fix this?
You need to send an array as sol so in Postman you should change sol with sol[0], sol[1], etc.. Then use this:
if (req.body.sol){
query.solutions = {"tags" : {$in: req.body.sol}}
}
Without the [] because req.body.sol is an array yet.
I have implemented a simple query build for nested objects:
const checkObject = (object) => {
let key;
const status = Object.entries(object).some(([objectKey, objectValue]) => {
if (typeof objectValue === "object" && objectValue !== null) {
key = objectKey;
return true;
}
return false;
});
return { status, key };
};
const queryBuilder = (input) => {
// Array verification not implemented
let output = {};
_.each(input, (value, key) => {
if (typeof value === "object" && value !== null) {
_.each(value, (nestedValue, nestedKey) => {
output[`${[key, nestedKey].join(".")}`] = nestedValue;
});
} else {
output[key] = value;
}
});
const cacheCheckObject = checkObject(output);
if (cacheCheckObject.status)
return { ..._.omit(output, cacheCheckObject.key), ...queryBuilder(output) };
return output;
};
I have not implemented array, but with some small work you can do it work. The same for Mongo operators. The complete example can be seen on Gist.