How to iterate over the following structure in Meteor Spacebars? - loops

I'm trying to group a collection by date in Meteor using Underscore's _.groupBy function.
Here is a sample of the code that outputs:
"Mon Dec 07 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"q9TMi9ZyoRjmddzfY",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-07T00:00:00.000Z",
"start":"2015-12-07T08:00:00.000Z",
"end":"2015-12-07T09:00:00.000Z",
"teachers":[
],
"clients":[
{
"clientId":"M4DDCGWGMzX7bJRHa",
"manual":"true"
}
],
"clientLimit":99
}
],
"Tue Dec 08 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"Jbchuc58zWDyEqnQZ",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T08:30:00.000Z",
"end":"2015-12-08T09:30:00.000Z",
"teachers":[
],
"clients":[
],
"clientLimit":15
},
{
"_id":"EsqygwCCPucGhx9nP",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T09:30:00.000Z",
"end":"2015-12-08T10:30:00.000Z",
"teachers":[
"eLExMRh3TT5eYWpki",
"wxFjH39M9kuBTv4zN"
],
"clients":[
],
"clientLimit":10
}
]
}
The problem is, I'm not really sure how I can output these in the front-end. Do I have to somehow convert it to normal arrays or a cursor? Or is there perhaps another way of grouping a collection by date headings?
I'm looking to output something like the following:
Saturday 21st September
- Item 1
- Item 2
Tuesday 24th September
- Item 3
Thanks for any ideas.

This is how I would do it:
loops.html
{{#each arrayify data}}
{{name}} <br>
<ul>
{{#each value}}
<li>ClientLimit: {{this.clientLimit}}</li>
{{/each}}
</ul>
{{/each}}
loops.js
Template.registerHelper('arrayify',function(obj){
result = [];
for (var key in obj) result.push({name:key,value:obj[key]});
return result;
});
Template.hello.helpers({
data: function() {
return {
"Mon Dec 07 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"q9TMi9ZyoRjmddzfY",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-07T00:00:00.000Z",
"start":"2015-12-07T08:00:00.000Z",
"end":"2015-12-07T09:00:00.000Z",
"teachers":[
],
"clients":[
{
"clientId":"M4DDCGWGMzX7bJRHa",
"manual":"true"
}
],
"clientLimit":99
}
],
"Tue Dec 08 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"Jbchuc58zWDyEqnQZ",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T08:30:00.000Z",
"end":"2015-12-08T09:30:00.000Z",
"teachers":[
],
"clients":[
],
"clientLimit":15
},
{
"_id":"EsqygwCCPucGhx9nP",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T09:30:00.000Z",
"end":"2015-12-08T10:30:00.000Z",
"teachers":[
"eLExMRh3TT5eYWpki",
"wxFjH39M9kuBTv4zN"
],
"clients":[
],
"clientLimit":10
}
]
}
});

Related

React Js Group By ID and Month from json using reduce or map function

I want convert my below existing json to new json so that I can dynamically populate dropdowns.
Here I am grouping by CityId and extracting month from DeptDate
However unable filter days based on CityId wise.
Existing JSON :
const [items] = useState([
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3762,"DeptDate":"22 Jul 2022 "},
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3763,"DeptDate":"05 Aug 2022 "},
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3764,"DeptDate":"12 Aug 2022 "},
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3765,"DeptDate":"19 Aug 2022 "},
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3766,"DeptDate":"26 Aug 2022 "},
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3767,"DeptDate":"09 Sep 2022 "},
{"Id":502,"CityId":2,"CityName":"Ex. Mumbai","DepartureId":3768,"DeptDate":"23 Sep 2022 "},
{"Id":502,"CityId":1,"CityName":"Ex. Ahmedabad","DepartureId":3762,"DeptDate":"22 Jul 2022 "},
{"Id":502,"CityId":7,"CityName":"Ex. Delhi","DepartureId":3762,"DeptDate":"22 Jul 2022 "},
]);
to New JSON :
[
{
"Id": 502,
"CityId": 2,
"CityName": "Ex. Mumbai",
"TravelDates": [
{
"DeptMonth": "Jul",
"Dept": [
{
"Day": "22"
"DepartureId": 3762,
}
]
},
{
"DeptMonth": "Aug",
"Dept": [
{
"Day": "05"
"DepartureId": 3763,
},
{
"Day": "12"
"DepartureId": 3764,
},
{
"Day": "19"
"DepartureId": 3765,
},
{
"Day": "26"
"DepartureId": 3766,
},
]
},
{
"DeptMonth": "Sep",
"Dept": [
{
"Day": "09"
"DepartureId": 3767,
},
{
"Day": "23"
"DepartureId": 3768,
}
]
}
]
},
{
"Id": 502,
"CityId": 1,
"CityName": "Ex. Ahmedabad",
"TravelDates": [
{
"DeptMonth": "Jul",
"Dept": [
{
"Day": "22"
"DepartureId": 3762,
}
]
}
]
},
]
Currently I am using below reduce function but unable to achieve expected result.
const newJson = items.reduce((cityGroup, { CityName, CityId, DeptDate, DepartureId }) => {
var [d, m, y] = DeptDate.split(' ');
const day = `${d}`;
const month = `${m}`;
if (!cityGroup[month]) {
cityGroup[month] = [];
}
// unable to group dates by month
cityGroup[month].push({
DeptMonth: month,
Dept: [{
Day : day,
DepartureId : DepartureId
}]
});
if (!cityGroup[CityName]) cityGroup[CityName] = [];
cityGroup[CityName].push({
CityName,
CityId,
TravelDates : [
{
// to be placed here...
}
]
});
return cityGroup;
}, {});
console.log(newJson);
Please guide and thank you in advance for all support !!
I always prefer immutable data structures. This is how you could achieve it. You should be able to fill in the blank for your solution as well from here.
const groupByCityAndTravelDates = (arr) => arr.reduce((acc , cur) => {
const existing = acc[cur['CityId']];
const [d , m , y] = cur['DeptDate'].split(' ');
if (existing) {
const existingTravelDate = acc[cur['CityId']]['TravelDates'][m];
if (existingTravelDate) {
return {
...acc ,
[cur['CityId']]: {
...acc[cur['CityId']] ,
'TravelDates': {
...acc[cur['CityId']]['TravelDates'] ,
[m]: {
'DeptMonth': m ,
'Dept': [
...acc[cur['CityId']]['TravelDates'][m]['Dept'] ,
{
'DeptDay': d ,
'DepartureId': cur['DepartureId'] ,
},
],
},
},
},
};
}
return {
...acc ,
[cur['CityId']]: {
...acc[cur['CityId']] ,
'TravelDates': {
...acc[cur['CityId']]['TravelDates'] ,
[m]: {
'DeptMonth': m ,
'Dept': [
{
'DeptDay': d ,
'DepartureId': cur['DepartureId'] ,
},
],
},
},
},
};
}
return {
...acc ,
[cur['CityId']]: {
'Id': cur['Id'] ,
'CityId': cur['CityId'] ,
'CityName': cur['CityName'] ,
'TravelDates': {
[m]: {
'DeptMonth': m ,
'Dept': [
{
'DeptDay': d ,
'DepartureId': cur['DepartureId'] ,
},
],
},
},
},
};
} , {});
const toCityArray = (mappedData) => Object.keys(mappedData).map(key => {
return {
'CityId': key,
'Id': mappedData[key]['Id'],
'CityName': mappedData[key]['CityName'],
'TravelDates': Object.keys(mappedData[key]['TravelDates']).map(travelKey => {
return {
'DeptMonth': travelKey,
'Dept': mappedData[key]['TravelDates'][travelKey]['Dept']
}
})
}
})
toCityArray(groupByCityAndTravelDates(arr))
I have some takeaways for you
You will have to consider year for aggregation alongwith month at some point of time in the solution.
In general, its recommmended to use camelCase for json attributes.
I am sure you are pulling this data from an api. Its not recommended to do a lot of aggregation on the frontend, specially if the data grows. If possible transfer this aggregation to the api.
Hope this helps.

MongoDB remove elements depending on element before (Iterating)

I want to remove ($unset) elements from my MongoDB Objects with condition if the same Object has a similar element.
My Object:
{
"_id": "5eabf8b144345b36b00bfbaa",
"ranktime": [{
"pos":"2",
"datum":"Mon May 05 2020 12:22:52 GMT+0200 (GMT+02:00)",
"source":"SOURCE2"
},{
"pos":"1",
"datum":"Fri May 01 2020 12:23:10 GMT+0200 (GMT+02:00)",
"source":"SOURCE1"
},{
"pos":"37",
"datum":"Fri May 01 2020 12:25:14 GMT+0200 (GMT+02:00)",
"source":"SOURCE2"
},{
"pos":"12",
"datum":"Fri May 01 2020 12:25:14 GMT+0200 (GMT+02:00)",
"source":"SOURCE2"
},{
"pos":"37",
"datum":"Fri May 01 2020 18:45:27 GMT+0200 (GMT+02:00)",
"source":"SOURCE2"
}]
}
So I want to remove the entry in ranktime if ranktime.source == "SOURCE2" and if the date is the same as with the object before. Actually I have to iterate through the single elements of ranktime. Is this possible in MongoDB ?
The Expected outcome would be:
{
"_id": "5eabf8b144345b36b00bfbaa",
"ranktime": [{
"pos":"2",
"datum":"Mon May 05 2020 12:22:52 GMT+0200 (GMT+02:00)",
"source":"SOURCE2"
},{
"pos":"1",
"datum":"Fri May 01 2020 12:23:10 GMT+0200 (GMT+02:00)",
"source":"SOURCE1"
},{
"pos":"37",
"datum":"Fri May 01 2020 12:25:14 GMT+0200 (GMT+02:00)",
"source":"SOURCE2"
}]
}
Basically you can use $reduce to process an array and define previous element using $let and $arrayElemAt statements. The new $set syntax allows you to use aggregation within update statement:
db.col.updateMany({}, [
{
$set: {
ranktime: {
$reduce: {
input: "$ranktime",
initialValue: [],
in: {
$let: {
vars: { last: { $arrayElemAt: [ "$$value", -1 ] } },
in: {
$cond: [
{
$and: [
{ "$eq": [ "$$last.source", "SOURCE2" ] },
{ "$eq": [ { $substr: [ "$$last.datum", 0, 15 ] }, { $substr: [ "$$this.datum", 0, 15 ] } ] },
]
},
"$$value",
{ $concatArrays: [ "$$value", [ "$$this" ] ] }
]
}
}
}
}
}
}
}
])
Aggregation Example

How to delete item in nested array to pass as react state

In a react class called CompanyDashboard have a state called data that is an array 3 of objects, each of those objects has a timeslots key that holds an array of timeslots.
Inside CompanyDashboard I have a functional component called CompanyPanel that takes in the value of one company and renders the timeslots as a list of clicable items.
When i click on any of those items I execute a method called deleteTime from CompanyDashboard that is being passed to CompanyPanel as props, with name and timeslot as arguments.
I want to delete from the state called data the specific timeslot of the specific company, which I am getting in the deleteTime method as arguments.
But i dont know how.
On the stateless functional component I have this:
<span className='pa2 red pointer ma2 bg-white' onClick={() => deleteTime(timeslot, company)}>X</span>
and then in the CompanyDashboard this method:
deleteTime (timeslot, company) {
// here i want to remove the specific timeslot from the spcific company from the state data
// and set it to this new state without that specific item inside that specific company
}
The data state looks like this:
data = [
{
"_id": "5db581e58e11ad1b933e7f42",
"name": "ZANITY",
"times": [
{
"timestamp": 1474607824073,
"dateUTCString": "Sat Sep 03 2016 19:01:09 GMT+0000 (UTC)",
},
{
"timestamp": 1389120349942,
"dateUTCString": "Mon Aug 19 2019 05:43:14 GMT+0000 (UTC)",
},
]
},
{
"_id": "5db581e584de79b380890f75",
"name": "VETRON",
"times": [
{
"timestamp": 1474607824073,
"dateUTCString": "Sat Sep 03 2016 19:01:09 GMT+0000 (UTC)",
},
{
"timestamp": 1389120349942,
"dateUTCString": "Mon Aug 19 2019 05:43:14 GMT+0000 (UTC)",
},
]
},
{
"_id": "5db581e565b82e2b729077e1",
"name": "KOZGENE",
"times": [
{
"timestamp": 1474607824073,
"dateUTCString": "Sat Sep 03 2016 19:01:09 GMT+0000 (UTC)",
},
{
"timestamp": 1389120349942,
"dateUTCString": "Mon Aug 19 2019 05:43:14 GMT+0000 (UTC)",
},
]
}
]```
you should add a unique id to the time stamps objects so they would be more distinguishable and easier to deal with, but for now, we can do:
deleteTime (timeslot, company) {
const newState = state.map(company=>{
company.times.filter(time=>{
return time.timestamp !== timeslot
})
return company
})
this.setState(newState) // or setState(newState) if you are functional
}
I found the answer, thought I think it could be done in a simpler way, in any case it works:
deleteTime (timeslot, name) {
const newState = this.state.data.map(company => {
if (name === company.name) {
let newTimes = company.times.filter(time => {
return time.dateUTCString !== timeslot.dateUTCString
})
company.times = newTimes
return company
}
return company
})
this.setState({data: newState}) // or setState(newState) if you are functional
}

JSON inline Date converting

I have D3 data graphic like here: https://www.metricsgraphicsjs.org/examples.htm#lines with example code
MG.data_graphic({
title: "Singleton",
description: "Handling a solitary data point.",
data: [{'date': new Date('2015-03-05T21:00:00Z'), 'value': 12000}],
width: 600,
height: 200,
right: 40,
target: '#singleton'
});
and difference is that I store data into database. But I have problem with displaying dates. My JSON data (pulled from MySQL) looks like this:
var data1 = [
[
{
"date": "2018-04-28T13:42:55Z",
"value": 20.8,
"added": "2018-04-28T13:42:55Z"
}
],
[
{
"date": "2018-04-28T13:42:55Z",
"value": 22.8,
"added": "2018-04-28T13:42:55Z"
}
],
[
{
"date": "2018-04-28T13:42:55Z",
"value": 23.9,
"added": "2018-04-28T13:42:55Z"
}
],
[
{
"date": "2018-04-28T13:42:55Z",
"value": 21.3,
"added": "2018-04-28T13:42:55Z"
}
]
];
When I try to display that data, it does not work, shows me errors like <path> attribute d: Expected number, "MNaN,86.570057581…"
But on other hand, if I set another variable for example
var data2 = [
[
{'date': new Date('2015-03-05T21:07:00Z'), 'value': 12000},
{'date': new Date('2015-03-05T21:10:00Z'), 'value': 5500},
{'date': new Date('2015-03-05T21:15:00Z'), 'value': 1000}
],
[
{'date': new Date('2015-03-05T21:05:00Z'), 'value': 18000},
{'date': new Date('2015-03-05T21:07:00Z'), 'value': 15000},
{'date': new Date('2015-03-05T21:15:00Z'), 'value': 7000}
]
];
This second example works and I was wondering what this "new Date()" does to data. How can I "fix" first data1 array and store it in another variable with correct dates? - I did try this type of date: Date Sat Apr 28 2018 13:56:55 GMT+0000 (UTC) but that did not help, did not work. Like this:
[
{'date': 'Apr 28 2018 13:57:55 GMT+0000 (UTC)', 'value': 18000},
{'date': 'Apr 28 2018 13:58:55 GMT+0000 (UTC)', 'value': 15000},
{'date': 'Apr 28 2018 13:59:55 GMT+0000 (UTC)', 'value': 7000}
]
This did not work. Does "new Date()" converts date and time to integer or string or something else?
I just want to find a way to change data1 variable and convert its dates to proper values to be able to show them on graph.
Thanks guys!

AngularJS - Filter view by month with ng-click

I would like to filter my view with a simple link. I have several objects which all contain a date. Eg. If I click March only data with "Startdate" March should be displayed. I searched the web but found nothing which worked for me. This is my json object and the criteria should be "Startdate".
trips.son
[{
"Startdate": "Thu Jan 02 2014 00:00:00 +0100",
"DAYS": [{
"DATE": "Thu Jan 02 2014 00:00:00 +0100",
"IATA": "TXL",
"DUTY": "6:10"
}]
}, {
"Startdate": "Sun Jan 05 2014 00:00:00 +0100",
"DAYS": [{
"DATE": "Sun Jan 05 2014 00:00:00 +0100",
"IATA": "CBTH",
"DUTY": "8:07"
}]
}, {
"Startdate": "Wed Sep 24 2014 00:00:00 +0200",
"DAYS": [{
"DATE": "Wed Sep 24 2014 00:00:00 +0200",
"IATA": "BCN",
"DUTY": "9:35"
}, {
"DATE": "Thu Sep 25 2014 00:00:00 +0200",
"IATA": "BCN",
"DUTY": "15:34"
}]
}, {
"Startdate": "Sat Sep 27 2014 00:00:00 +0200",
"DAYS": [{
"DATE": "Sat Sep 27 2014 00:00:00 +0200",
"IATA": "CPH",
"DUTY": "4:44"
}]
}]
Here you can see what I mean:
UPDATED: plnkr
By default only January should by displayed - changing the view when each link is clicked !
I found a way which works for me ! Maybe not the best but it will do the job.
Added StartdateMonth as the name of the month to my scope:
var date = new Date($scope.trips[i].Startdate);
$scope.trips[i].Startdate = date;
var names = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
$scope.trips[i].StartdateMonth = names[date.getMonth()];
create ng-click for tab:
<li role="presentation"><a ng-click="myFilter = {StartdateMonth: 'Januar'}">Januar</a></li>
<li role="presentation"><a ng-click="myFilter = {StartdateMonth: 'Februar'}">Februar</a></li>
finally add the filter:
<div ng-repeat="trip in trips | filter: myFilter">

Resources