How to sort nested array of objects by date - javascript

I am creating simple News application, And i am using Firebase as back-end, I have stored News articles in Cloud firestore, In my fields i have News publication time hr:min:sec I want to sort received data by publication time, from the latest to the oldest, any solutions? Thanks in advance
var data = [
{ news: [
{ published_at: "2/22/2021",
imgUrl: "",
id: 159783,
title: "short descr",
date: "18:11:53",
previewText: "some kind of title" }
],
newsId: "5GTAbGLfS0hSCOkmTfHD"
},
{ news: [
{ id: 159783,
published_at: "2/22/2021",
previewText: "some kind of title2",
title: "short descr",
date: "17:19:53",
imgUrl: ""
}
],
newsId: "lw2hzVe0m3dbcmvBj4Vz" }
]
data.forEach((item)=>{
var singleItem = item.news
const finalResult = singleItem.sort((a, b) => b.date - a.date)
console.log(finalResult)
})

You can use string#localeCompare to sort time in hh:mm:ss format.
const data = [ { news: [ { published_at: "2/22/2021", imgUrl: "", id: 159783, title: "short descr", date: "18:11:53", previewText: "some kind of title" } ], newsId: "5GTAbGLfS0hSCOkmTfHD" }, { news: [ { id: 159783, published_at: "2/22/2021", previewText: "some kind of title2", title: "short descr", date: "17:19:53", imgUrl: "" } ], newsId: "lw2hzVe0m3dbcmvBj4Vz" } ];
data.sort((a,b) => b.news[0].date.localeCompare(a.news[0].date));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I think you can do something like this
const finalResult = singleItem.sort((a, b) => Date.parse(`${b.published_at} ${b.date}`) - Date.parse(`${a.published_at} ${a.date}`))

Related

I need to filter an array of object that contains an array of object

So here's my data, I need to reduce? or filter it based on the given search string.
const contents = [
{
title: "Accounts",
links: [
{
header: "Accounts by Status",
},
],
},
{
title: "Executions",
links: [
{
header: "Purchase and Sales",
},
{
header: "AMLA Transactions Proof List",
},
{
header: "Account Ranking",
},
{
header: "Trading Summary",
},
],
},
];
const search = "account";
console.log(
contents.filter((content) =>
content.links.some((link) =>
link.header.toLowerCase().includes(search.toLowerCase())
)
)
);
.as-console-wrapper { max-height: 100% !important; }
Can someone guide me in the right direction? I think reduce with filter can do the job but I don't know where to start. Thanks!
If my search string is 'account'
My desired output should be something like this
[{
title: 'Accounts',
links: [{
header: 'Accounts by Status'
}]
},
{
title: 'Executions',
links: [{
header: 'Account Ranking'
}]
}
]
You need to rebuild content with links, if they match.
const
contents = [{ title: 'Accounts', links: [{ header: 'Accounts by Status' }] }, { title: 'Executions', links: [{ header: 'Purchase and Sales' }, { header: 'AMLA Transactions Proof List' }, { header: 'Account Ranking' }, { header: 'Trading Summary' }] }],
search = 'account',
result = contents.flatMap(content => {
const links = content.links.filter(({ header }) => header
.toLowerCase()
.includes(search.toLowerCase())
);
return links.length
? { ...content, links }
: [];
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This solution filters the links array by search string, and if non is found removes the item all together. The test input contains one more item that produces no hit: { title: 'No hit', links: [{ header: 'Something else' }] }
const input = [
{ title: 'Accounts', links: [{ header: 'Accounts by Status' }] },
{ title: 'Executions', links: [{ header: 'Purchase and Sales' }, { header: 'AMLA Transactions Proof List' }, { header: 'Account Ranking' }, { header: 'Trading Summary' }] },
{ title: 'No hit', links: [{ header: 'Something else' }] }
];
const searchString = 'account';
// for performance perform lowercase once ahead of time:
const search = searchString.toLowerCase();
const result = input.map(obj => {
let arr = obj.links.filter(o => o.header.toLowerCase().includes(search));
if(arr.length) {
// don't change original input, but return a filtered copy
return {
title: obj.title,
links: arr
};
} else {
return null;
}
}).filter(Boolean);
console.log(result);

Best way to return a nested object the matches a property requested

I'm trying to create a new object that only contains the a product array with the seller I req. I have an order object that has a product array. I'd like to return a specific seller. I tried:
const newOrders = orders.map((element) => {
return {
...element,
product: element.product.filter(
(seller) => seller === req.currentUser!.id
),
};
});
does mongoose have a preferred method for doing what I bring to achieve? I've read through the find queries but none of the methods seem useful to this use case.
orders: [
{
userId: "638795ad742ef7a17e258693",
status: "pending",
shippingInfo: {
line1: "599 East Liberty Street",
line2: null,
city: "Toronto",
country: "CA",
postal_code: "M7K 8P3",
state: "MT"
},
product: [
{
title: "new image",
description: "a log description",
seller: "6369589f375b5196f62e3675",
__v: 1,
id: "63737e4b0adf387c5e863d33"
},
{
title: "Mekks",
description: "Ple",
seller: "6369589f375b5196f62e3675",
__v: 1,
id: "6376706808cf1adafd5af32f"
},
{
title: "Meeks Prodyuct",
description: "long description",
seller: "63868795a6196afbc3677cfe",
__v: 1,
id: "63868812a6196afbc3677d06"
}
],
version: 1,
id: "6388138170892249e01bdcba"
}
],
Im sure this can be improved, doesn't feel that its the best way possible but it gets the result. Like the previous answer you have to find first the order the seller is in then find the products than filter the seller by the id. I'm using typescript and there's a bug https://github.com/microsoft/TypeScript/issues/50769 so you have to use the bracket notation.
const orders = await Order.find({
"product.seller": req.currentUser!.id,
});
const allOrders = orders[0].product;
const sellerOrders = allOrders.filter((obj) => {
return obj["seller"] === req.currentUser!.id;
});

Filtering and maping in nested arrays

My task is to filter objects by values in nested arrays. like in example below:
const array = [
{
authorId: '62222a1cea00a0601f200142',
description: [
[
{
title: 'English description',
paragraph: 'And english paragraph!!!!',
},
],
[
{
title: 'some title!!!',
paragraph: 'some para!!',
},
],
],
removed: false,
status: 'NEW',
},
{
authorId: '621f97562511255efa0f135e',
description: [
[
{
title: 'EEEE',
paragraph: 'aaaa',
},
],
],
removed: false,
status: 'NEW',
},
{
description: [
[
{
title: 'TEST',
paragraph: 'TESR',
},
],
],
removed: false,
status: 'NEW',
},
{
authorId: '621f97432511255efa0f135c',
description: [
[
{
title: 'My task',
paragraph: 'Parapgraph 19',
},
],
],
removed: false,
status: 'NEW',
},
]
my expected results is something like that, based on search input, which is conts searchInput
const searchInput = "par"
const array = [
{
authorId: '62222a1200142',
description: [
[
{
title: 'English description',
paragraph: 'And english paragraph!!!!',
},
],
[
{
title: 'some title!!!',
paragraph: 'some para!!',
},
],
],
removed: false,
status: 'NEW',
},
{
authorId: '6a000142',
description: [
[
{
title: 'TEST',
paragraph: 'paragraph one',
},
],
],
removed: false,
status: 'NEW',
},
]
Ive already try something like this:
const results = array?.map((el) => el?.description.map((i) => i.map((item) => item.paragraph))).filter((description) =>description.toString().toLowerCase().includes(searchValue))
But it return only arrays with paragraphs and i expected to filter whole objects, with all data, not only strings
You need to put the map inside the filter, so your data isn't modified. You use first map the description paragraphs into an array and check if all the values of the paragraphs includes the searched param.
const searchValue = 'para';
const array = [{authorId: '62222a1cea00a0601f200142',description: [[{title: 'English description',paragraph: 'And english paragraph!!!!',},],[{title: 'some title!!!',paragraph: 'some para!!',},],],removed: false,status: 'NEW',},{authorId: '621f97562511255efa0f135e',description: [[{title: 'EEEE',paragraph: 'aaaa',},],],removed: false,status: 'NEW',},{description: [[{title: 'TEST',paragraph: 'TESR',},],],removed: false,status: 'NEW',},{authorId: '621f97432511255efa0f135c',description: [[{title: 'My task',paragraph: 'Parapgraph 19',},],],removed: false,status: 'NEW',},];
const results = array.filter(el => {
return el.description
.map(i => {
return i.map(item => item.paragraph)
})
.every((description) => {
return description.toString().toLowerCase().includes(searchValue)
})
});
console.log(results);
I didn't tested the function, however it should work. Put the questionmarks when needed.
I think the filter should be on the array itself, since that is what you expect to be the result.
I used the some function to resolve the arrays in the object.
array?.filter(el=>el?.description.some(el2=>el2.some(el3=>el3?.paragraph.toString().toLowerCase().includes(searchValue))))
It's easier to understand if you don't have everything on one line.
Use filter to return a new array of objects where the description (inner) array has an at leasr one object that contains a paragraph containing the query.
const array=[{authorId:"62222a1cea00a0601f200142",description:[[{title:"English description",paragraph:"And english paragraph!!!!"}],[{title:"some title!!!",paragraph:"some para!!"}]],removed:!1,status:"NEW"},{authorId:"621f97562511255efa0f135e",description:[[{title:"EEEE",paragraph:"aaaa"}]],removed:!1,status:"NEW"},{description:[[{title:"TEST",paragraph:"TESR"}]],removed:!1,status:"NEW"},{authorId:"621f97432511255efa0f135c",description:[[{title:"My task",paragraph:"Parapgraph 19"}]],removed:!1,status:"NEW"}];
const query = 'par';
const out = array.filter(outer => {
// Return an object when the inner array
// of the function has some object that
// contains a paragraph containing the query
return outer.description.some(arr => {
return arr.some(inner => {
return inner.paragraph
.toLowerCase()
.includes(query);
});
});
});
console.log(out);
Additional documentation
some
have you tried .reduce()? It is combination of .map() and .filter() as you can see here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
Takes some time to get into .reduce(), but once you get it, you will like it!

react count object properties in an array

I am fetching data by an API. It is a movie, tv show, person database. When I search a word in the search box, it returns the related movie, tv show and person names in objects nested in an array. for example when I search "fight":
[
0:{original_name: "쌈 마이웨이", id: 70813, media_type: "tv", name: "Fight My Way", vote_count: 5,…}
1:{vote_average: 8.2, vote_count: 8057, id: 550, video: false, media_type: "movie", title: "Fight Club",…}
2:{vote_average: 6.1, vote_count: 215, id: 345922, video: false, media_type: "movie",…}
3:{original_name: "Fight", id: 46554, media_type: "tv", name: "Fight", vote_count: 0, vote_average: 0,…}
4:{original_name: "The Good Fight", id: 69158, media_type: "tv", name: "The Good Fight", vote_count: 22,…}
5:{vote_average: 0, vote_count: 0, id: 158301, video: false, media_type: "movie", title: "Fight",…}
]
there are more results but I cut them. As you can see there are media_type properties in each object. there are 3 media types as you can understand (movie, tv, person). I want to count each type.
actually; I want the same thing in the link I guess: React: Syntax for calling setState in Switch Return
but it doesn't work for me. I tried to change simply the state of movieCount to 3 like this:
countType() {
this.props.movies.map(movie => {
return() => {
if(movie.media_type === 'movie') {
this.setState({ movieCount: 3});
console.log(this.state);
}
}
});
}
but it doesn't work too.and I researched on the internet this stuff in javascript documentation and forums. not about just react. but I couldn't do anything. I know it's simple.
so how can I count objects in an array according to their property types?
Assuming that the data you fetched from API is stored in data variable, you can try the following code to find the count of movie media type in your data array:
const movies = data.filter(item => item.media_type === 'movie'));
const moviesCount = movies.length;
You can also dynamically calculate count of every media_type in your data array:
const mediaTypes = data
.map(dataItem => dataItem.media_type) // get all media types
.filter((mediaType, index, array) => array.indexOf(mediaType) === index); // filter out duplicates
const counts = mediaTypes
.map(mediaType => ({
type: mediaType,
count: data.filter(item => item.media_type === mediaType).length
}));
Then counts will be something like this:
[
{
"type": "tv",
"count": 3
},
{
"type": "movie",
"count": 3
}
]
ok i found the solition. thank you to poohitan for answer. i solved it
through his answer.
countType(type) {
const countTypes = this.props.movies.filter(movie => movie.media_type === type);
return countTypes.length;
}
and while i am rendering my tv results, i just call the method above with type. for example:
return (
<div>
movie count: {this.countType('movie')}
tv show count: {this.countType('tv')}
</div>
);
var data = [
{ original_name: "쌈 마이웨이", id: 70813, media_type: "tv", name: "Fight My Way", vote_count: 5 },
{ vote_average: 8.2, vote_count: 8057, id: 550, video: false, media_type: "movie", title: "Fight Club" },
{ vote_average: 6.1, vote_count: 215, id: 345922, video: false, media_type: "movie" },
{ original_name: "Fight", id: 46554, media_type: "tv", name: "Fight", vote_count: 0, vote_average: 0 },
{ original_name: "The Good Fight", id: 69158, media_type: "tv", name: "The Good Fight", vote_count: 22 },
{ vote_average: 0, vote_count: 0, id: 158301, video: false, media_type: "movie", title: "Fight" },
]
this.types = {};
data.forEach((d) => {
if (!this.types[d["media_type"]]) {
this.types[d["media_type"]] = 1;
} else {
this.types[d["media_type"]] += 1;
}
})
console.log(this.types);
// you will get answer { tv: 3, movie: 3 }
Here's one possible way:
render() {
let countTypes = ' '
return ({
list.length > 0
?
<span> {countTypes = (list.filter(moviesFilter =>
moviesFilter.type.id === this.props.typeId)).length}
</span>
:
<DisplayMessage message="0" />
})
}

Javascript Array Manipulation - Is there a more declarative approach?

Thanks for taking a look here. I'm working with an API, and need to change the format of the data. Here's an example of the return data:
data: [
{
status: "planned work",
name: "123"
},
{
status: "all good",
name: "nqr"
}
];
Each train line has a name like "123" or "nqr", and I want to split each train into their own objects so that it would look something like this:
data: [
{
status: "planned work",
name: "1"
},
{
status: "planned work",
name: "2"
},
{
status: "planned work",
name: "3"
},
{
status: "all good",
name: "n"
},
{
status: "all good",
name: "q"
},
{
status: "all good",
name: "r"
}
];
I have some working code which splits the name and uses nested .forEach loops to push items to an array. Working code:
function formatLinesData(lines) {
var trains = [];
lines.forEach( line => {
line.name.split("").forEach(train => {
trains.push({name: train, status: line.status});
});
});
return trains;
}
Is there a way to accomplish this without the nested loops? Looking for an elegant solution if you have one.
Thanks
You might do as follows;
var data = [
{
status: "planned work",
name: "123"
},
{
status: "all good",
name: "nqr"
}
],
newData = [].concat(...data.map(o => o.name.split("").map(c => ({status: o.status, name: c}))));
console.log(newData);
You can use reduce - initialize it with an empty array, and iterate over the data
array using your logic.
data.reduce((prev,curr) => {
for (let i=0; i<curr.name.length; i++) {
prev.push({ name : curr.name[i], status : curr.status});
}
return prev;
},[]);

Categories