Search Function on AngularFireList in Ionic - javascript

I am having a bit of trouble wrapping my head around getting this search function to work. I have it setup right now so it will get the right item when I search it but it's spelling has to be exact including capitalization and punctuation. I want it to be able to get the item regardless of the users search term's capitalization and if they just typed the letter 'b' it will include all items that have a 'b' in the items fields.
I know that I want to query the call to the database since it would be quite heavy to do it on the client side but what do you guys think or how would you go about achieving this?
setFilteredItems() {
this.employeeListRef = this.database.list('userProfile',
ref=> ref.orderByChild('lastName'));
this.employeeList = this.employeeListRef.snapshotChanges()
.map(
changes => {
return changes.map(c => ({
key: c.payload.key, ...c.payload.val()
}))
}
);
//if searchterm is null it returns so it can set back the list to all values
//searchterm is declared in constructor
if(!this.searchTerm) {
return;
}
//var term = this.searchTerm.toLowerCase();
this.employeeListRef = this.database.list('userProfile',
ref => ref.orderByChild('lastName').equalTo(term));
this.employeeList = this.employeeListRef.snapshotChanges()
.map(
changes => {
return changes.map(c => ({
key: c.payload.key, ...c.payload.val()
}))
}
);
}

If you look at the ASCII table you can get a good idea of how Firebase stores it's records and why orderByChild might not work as you expect.
b is 98 and B is 66. Their in different positions on the ASCII table.
There are two things you can try to help you access the data in the expression you want.
Try converting the searchable data to lowercase with the user of database methods
Use a cloud function and on-write of a record, save a lowercase version of that record in the object, then search by that record. An example would be;
{ lastName: 'Smith', lowercaseLastName: 'smith' }
You then orderByChild('lowercaseLastName').

Related

I'm trying to make an array with only values ​that are not contained in the other array (non-repeating)

I have an array of available users that can be invited and also another array with all joined users to the particular chat. I need to check which of the available users have joined the chat and should be listed elsewhere.
Finally, I want to get an array with only the available users who have not joined the chat.
let availablеUsers = [{id:1,name:'Dani'}, {id:2,name:'Ani'}, {id:3,name:'Marta'}]
let allUsers = [{id:2,name:'Ani'},{id:10,name:'John'}, {id:3,name:'Marta'}]
The first thing I try to do is find those who are already participating in the chat:
let joinedUsers = availablеUsers.map((user) => {
return allUsers?.find((u) => u.id === user.id);
});
And i get this : [undefined, {… Аni}, {… Marta}]
Then I try to filter the array of available users so that I remove from it those that are in the newly created array and here's the problem I don't know how to do this :/
My idea is something like that:
availablеUsers = availablеUsers.filter((user) => {
//HERE I don't know what logic to write
return joinedUsers?.map((m) => m?.id !== user.id); // this doesn't work, just an example
});
My goal is to have only those users not contained in the other remain in the availableUsers array.
In the example I have given at the end in the array should remain only {id:1,name:'Dani'}
I welcome any suggestions. If it can do it with chaining, without the extra variable for joinedUsers it would be even better!
There's no need for joinedUsers. Just use find() or some() in the filter() callback, and invert the test.
availableUsers = availableUsers.filter(user => !allUsers.some(u => u.id == user.id))
if users are uniquely identified by id you can use just a filter with a Set of known users:
let availablеUsers = [{id:1,name:'Dani'}, {id:2,name:'Ani'}, {id:3,name:'Marta'}]
let allUsers = [{id:2,name:'Ani'},{id:10,name:'John'}, {id:3,name:'Marta'}]
let joinedUsers = availablеUsers.filter(
function ({id}) {
return this.has(id);
},
new Set(allUsers.map(({id}) => id))
);
Accordingly, you can use the same to update availablеUsers in one go:
availablеUsers = availablеUsers.filter(
function ({id}) {
return !this.has(id);
},
new Set(allUsers.map(({id}) => id))
);
it's not super clear why or when you need !== vs === but the concept is: use a set and use filter instead of map when you want to filter + a Set works harder while constructed but it's blazing fast while used via has()

Searching Array of Objects with two search values

so I am trying to make an app that has two search criterias. The front-end app basically fetches data and you have two search bars to filter out the incoming data.
One search is by name and the other is by school name, the tricky part is that the either of the search also takes into account if there is some value in the other search parameter.
For example, if you search for "California University" and "Bob", you should get only Bobs that go to California University to render on the screen. But it seems like right now my DOM only renders the most recent search Ive made. What is the best way to go about a filter that filters both student name and school name using an event listener (keyup) on the search inputs?
searchByNameInput.addEventListener("keyup", (e) => {
const filterNameArray = studentArray.filter((student) => {
// code here to filter students with this name and render it on DOM
}
}
searchBySchoolName.addEventListener("keyup", (e) => {
//filters students who go to this school and render it on DOM
}
}
Write a single filtering function that checks both inputs, and call it from both event listeners.
function filterStudents() {
const nameFilter = searchByNameInput.value;
const schoolFilter = searchBySchoolName.value;
const filterArray = studentArray.filter(student =>
(nameFilter == '' || student.name.includes(nameFilter) &&
(schoolFilter == '' || student.school.includes(schoolFilter))
}
searchByNameInput.addEventListener("keyup", filterStudents);
searchBySchoolNameInput.addEventListener("keyup", filterStudents);
first filter your object and please try it include() method instead of filter().
as a above example
here filterData is my new filtered object and stu_data is my array.
get all search value from search input.
Example:-
var filterData = stu_data.filter((stu_filter) => {
return (stu_filter.firstname.toLowerCase().includes(filter) ||
stu_filter.lastname.toLowerCase().includes(filter))})
I hope this is help for you!
happy coding :)

Accessing the first value of the first key in an object

I am having a little bit of an issue trying to get the value of a certain object. Since this is a bit hard to explain, I'll set up a scenario that follows what I need.
{"Gmail": {"example#example.com": "password1", "anotherexample#example.com": "password2}, ...}
I have an object (as represented above, we will call the object "encrypted"). I can get the value "Gmail" by using Object.keys(encrypted)[i] where i represents the index I'm looking for. The issue I am encountering is, how do I get exaxmple#example.com or password1?
I've been aimlessly wandering around it for a while trying to figure this out, searching for answers, but I can't seem to do so or find any that aren't based on arrays. Any help is great, thank you!
You could use Object.entries
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
This turns objects into arrays of key - value which you can traverse, an example would be something like:
const data = {
"Gmail": { "example#example.com": "password1", "anotherexample#example.com": "password2" },
"Gmail2": { "example#example.com": "password1", "anotherexample#example.com": "password2" },
};
Object.entries(data).forEach(([key, value]) => {
const emailProvider = key;
const emailList = Object.entries(value);
console.log({ mail: emailProvider });
emailList.forEach(([email, password]) => {
console.log({ email, password })
})
});

Filter an Array of Objects from an Array in TypeScript

I built a custom component that filters an array of objects. The filter uses buttons, sets from active to non-active and allows more than one option on/off at the same time.
StackBlitz of my attempt - https://stackblitz.com/edit/timeline-angular-7-ut6fxu
In my demo you will see 3 buttons/options of north, south and east. By clicking on one you make it active and the result should include or exclude a matching "location" either north, south and east.
I have created my methods and structure to do the filtering, I'm struggling with the final piece of logic.
So far I have created a method to create an array of filtered locations depending on what the user clicks from the 3 buttons.
Next this passes to my "filter array" that gets the logic that should compare this filtered array against the original to bring back the array of results that are still remaining.
Its not quite working and not sure why - I originally got this piece of functionality working by using a pipe, but fore reasons do not want to go in that direction.
//the action
toggle(location) {
let indexLocation = this.filteredLocations.indexOf(location);
if (indexLocation >= 0) {
this.filteredLocations = this.filteredLocations.filter(
i => i !== location
);
} else {
this.filteredLocations.push({ location });
}
this.filterTimeLine();
}
// the filter
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
//the logic
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
https://stackblitz.com/edit/timeline-angular-7-ut6fxu
Sorry for my expression but u have a disaster in your code. jajaja!. maybe u lost that what u need but the logic in your functions in so wrong. comparing string with objects. filter a array that filter the same array inside... soo u need make a few changes.
One:
this.filteredLocations.push({location});
Your are pushing object. u need push only the string.
this.filteredLocations.push(location);
Two:
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
in this function you filter the timeLine array. and inside of contactMethodFilter you call filter method to timeLine again....
See a functional solution:
https://stackblitz.com/edit/timeline-angular-7-rg7k3j
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
This function is not returning any value and is passed to the .filter
Consider returning a boolean based on your logic. Currently the filter gets undefined(falsy) and everything would be filtered out

Making a case-insensitive "like" query using the mongodb driver in Node

I'm looking to make a query like mentioned in the title with an array of data.
I have this line working..
collection.find({"name": {"$in":[/papa JOhn's/i,"Taco Bell"]}}).toArray(function(err, items) {
However, the data is going to be dynamic and fed into the query as an array
restaurant_data = [rest1, rest2 .... restn]
I want to essentially have something like
collection.find({"name": {"$in": /restaurant_data/i }}).toArray(function(err, items) {
My Attempt..
let test_data = ['papa john', 'taco bell']
//Get an array of the restaurant names here
collection.find({"name": {"$in": test_data.map(element => {
/element/i
})}}).toArray(function(err, items) {
My working attempt!
I got it doing this... Not sure if it's the most efficient
let test_data = ['papa john', 'taco bell']
collection.find({"name": {"$in": test_data.map((element) => {
var regex = new RegExp(".*" + element + ".*");
return regex
})}}).toArray(function(err, items) {
collection.find({"name": {"$in":
restaurant_data.map(e => new RegExp(e, 'i'))
}}).toArray
has better chance to work. Note that /bla/i will match blabla so
collection.find({"name": {"$in": [/bla/i] } })
will match documents with name blabla Not sure this is what you want or not.
If you're using mongodb 3.2+ I'd recommending you using the property Collation as using Regex might make the queries quite slower, you can use it in both creating indexes as well as querying:
db.peeps.createIndex({UserName:-1}, { collation: {locale:'en', caseLevel:false, caseFirst: "off"} )
db.peeps.find({UserName:'bob'}).collation({locale:'en', caseLevel:false, caseFirst: "off"}) // 3 results!
However, as I've faced this problem as well when I tried using collation it made my queries at least 2 times slower so I ended up sticking with inserting lowerCase data in mongodb and then validating and using toLowerCase in the payload fields instead of using Collation.

Categories