mach beginning javascript with Array - javascript

Good afternoon, I am trying to make a method that tells me the number of elements an Array has that starts with "RT:"
For this I have developed the following code:
public getRowsRTs(idProyecto){
this.twitterService.getTargets().subscribe((data) => {
this.Twitter = data;
});
let countRT = this.Twitter.filter( tweet => tweet.message.startsWith("RT:")).length;
return countRT;
}
}
Here, data returns all the Documents that Mongo extracts, and puts them in the Twitter Array that I have defined at the beginning of the component. Within this Array each element has different attributes, such as _id, message, date ... I want you to tell me how many of those documents, the message value, begins with RT: and to return it to me, this code , it does not give me any problem, but it does not give me absolutely nothing, I do not know if someone could help me.

If the array is filled with strings, this should work:
let regixForRTStart = /^RT:/;
startArray = ['RT:1', 'RT:2', 'Other', 'Stuff'],
count = startArray.filter(item => regixForRTStart.test(item))
// length
console.log(count.length);

use filter and startsWith methods.
const arr = [
{ message: "abc" },
{ message: "RT:" },
{ message: "RT: 2" },
{ message: "test" }
];
const count = arr.filter(({ message }) => message.startsWith("RT:")).length;
console.log(count);

Related

Filter array of objects if property value includes the string passed to it

I have an array of object as follows
const myArray = [
{
id:31,
name: "test"
},
{
id:22
name: "transit"
},
{
id:25
name: "tomato"
}
];
Now here is the scenario, user starts entering the text, if users enters t as input, i will get all 3 objects in the result because the name property has text t at the start (test, transit, tomato)
Now user enters to at the input, i want only the object with name tomato in the result.
In order to achieve this above scenario, i implemented the following
const propsToCheck = ['name'];
const userInput = 'To';
let result = myArray.filter(o =>
propsToCheck.some(k => userInput.toLowerCase().includes(String(o[k]).toLowerCase())
)
);
It doesnot provide correct result. can someone please let me know if i am doing it right or if there is any easy implementation to achieve the same result.
You're doing it the wrong way - you should be testing if the input is included in the string, not if the string is included in the input:
let result = myArray.filter(o =>
propsToCheck.some(k => String(o[k]).toLowerCase().includes(userInput.toLowerCase()))
);

Adding a value into an existing object in a list of objects based on the index

Background of my issue:
To start I had an array of objects each containing a user-ID called entries. I had to make an api call using the id inside each of those object to get the users full profile containing their fullName. I was able to map over the results of the api call to get a list of all users that had matching id's to the initial list I started with and with that I also pulled out their fullName this variable is labeled matches. So now I have the initial list [array] of userID's entries, along with a list of arrays of all the ID matches I found inside that list from my api call matches this list of arrays contains the ID and a Name.
What I am trying to do now is map over the entries and matches to compare userID's and if a match is found then I want to insert the name inside matches into the entry the match is found in based on the index. However I am not sure how to properly insert a key value pair inside of and object based on index or if im approaching this the correct way. Here is my code:
useEffect(() => {
const loadAllProviders = async () => {
//TODO: Make conditional if entries exists
try {
//get all providers
const results = await api.Providers.listnoAudit({ scope: "all" });
const allProviders = results.items;
//map over the entries to get providerId's out
const providerIDs = entries.map((entry) => entry.createdBy);
//map over response to get out provider names and id's
const idName = allProviders.map((provider) => [provider.id, provider.fullName]);
//find if any returned providers have matching ids to the ones in entries
const matches = idName.filter((match) => providerIDs.includes(match[0]));
//TODO: map over entries
// if matches[0] = entries.createdby then
//push matches[1] (name) into the object at the index where match occurs
entries.map((entry, idx) => {
matches.map((provider) => {
if (entry.createdBy === provider[0]) {
let en = {...entry, fullName: provider[1]}
}
})
});
} catch (err) {}
};
loadAllProviders();
}, [entries]);
Inside my if statement youll see my attempt to add the fullName to the entry using the spread operator but Im not sure how to actually replace the old object with the new object. When I console out en, I get the items that have been modified... I am pretty new to coding and any advice would be helpful.
You can probably reduce your allProviders list to get what you want. See the following example.
let allProviders = [
{id: 1, name: "Amy"},
{id: 2, name: "Kamala"},
{id: 3, name: "Stacy"},
{id: 4, name: "Sunil"}
]
let entries = [{createdBy: 2}, {createdBy: 4}]
let providerIds = entries.map(e => e.createdBy)
let result = allProviders.reduce((matches, provider) => {
if(providerIds.includes(provider.id)) {
matches.push({ ...provider, createdBy: provider.id})
}
return matches;
},[])
console.dir(result)

How can I filter through an array of objects based on a key in a nested array of objects?

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');

JS: Object value depending on regEx match

There are some objects in an array like this:
const result = [
{
"_id": "Dn59y87PGhkJXpaiZ",
"title": "Something",
"synonyms": [ "Anything", "else" ]
},
{ ... }
]
I do get this result by performing this:
Content.find({
$or: [
{ title: { $regex: new RegExp(term, 'i') } },
{ synonyms: { $regex: new RegExp(term, 'i') } }
]
}).toArray()
As you can see, I'm searching for title (string) or synonym (array) elements by a given search term.
So searching for some or any will give me the first document as my result.
In my component I do the output of the data like this:
render () {
return result.map((link, index) => {
return <Dropdown.Item
text={link.title}
key={index}
/>
})
}
But right now I do get the output Something for the dropdown item if I'm searching for any (term). For the user this doesn't make sense.
Of course any should give me the output Anything and some should give me the output Something.
In this example you can also search for thing and I would expect two output elements (of one single result document): Anything and Something.
I'm not quite sure how to modify the code to get this result. I think the best place to modify should be the react component (output) - not the server request result.
You could issue two separate queries on the server side to maintain clearly which part of your document was matched. This would ensure that for the doc which matches using synonyms was not used to return title.
const matchingTitles = Content.find(
{ title: { $regex: new RegExp(term, 'i') } }
}, {title: 1} ).toArray().map(x => x.title);
const matchingSynonyms = Content.find(
{ synonyms: { $regex: new RegExp(term, 'i') } }
}, {synonyms: 1} ).toArray().map(x => x.synonyms).reduce((x, y) => x.concat(y), []);
return Array.from(new Set([...matchingTitles, ...matchingSynonyms]));
I fetch the strings separately using two queries and then take the set union of them.
And on client side you could use these strings directly to display the search result.

JavaScript Matching one array with another?

above i have the picture of my arrays, below code i have mapped 2 sets of array .Purpose of this function is to make '_polygons' empty array. i have a rest service which is 'this.siAsset.updateComponent(_id, _polygons)' that is designed to update each asset. only thing is, i cant seem to pass an array of data to the update component service i have, its designed to take one id and one object as a parameter (if there is a way around , please provide) as you can see by the picture, both _id and _polygons have arrays of id's an arrays of objects. Question is, how can i loop and match to call the rest to go through each id and object instead of calling by writing the code 9 times like this.siAsset.updateComponent(_id[0], _polygons[0]) ...this.siAsset.updateComponent(_id[9], _polygons[9])
deleteAllZones = () => {
let assetVal = this.asset.$$state.value
console.log('tenant', assetVal)
let _polygons = assetVal.map(function (a) {
a.polygon = []
return a
})
console.log('a',_polygons)
let _id = assetVal.map(function (a) {
let id = a.id
return id
})
console.log('id',_id)
let message = this.$filter('translate')('SI-MESSAGES.DELZONE-MSG');
let title = this.$filter('translate')('SUBHEADER.DELZONE-TITLE');
let button = this.$filter('translate')('BUTTON.DELETE');
this.siAlertDialog.confirm(message, title, button)
.then(() => {
this.siAsset.updateComponent(_id, _polygons).then(() => {
this.toastIt.simple(this.$filter('translate')('SI-MESSAGES.ZONE-DELETED'))
}, (err) => {
this.siAlertDialog.error();
}
)
})
}
Your code snippet doesn't work. I've made dummy entries. This should give you an idea. Basically, you need to loop over one array and use the index to find corresponding items in the second
// Mocking data here
let assetVal = [{
id: 1
},
{
id: 2
},
{
id: 3
}
]
let _polygons = assetVal.map(function(a) {
a.polygon = []
return a
})
//console.log('a', _polygons)
let _id = assetVal.map(function(a) {
let id = a.id
return id
})
//console.log('id', _id)
// Mocking done
let updateComponent = (id, polygon) => {
return new Promise((resolve, reject) => {
resolve({
id,
polygon
})
})
}
_id.forEach((id, i) => {
updateComponent(id, _polygons[i]).then(result => {
console.log(result)
})
})
Also, by looking at your code, it doesn't look like your updateComponent method needs id to be passed as a parameter as it is already present in the polygon as well. Maybe you want to refactor that.

Categories

Resources