So I need to take data only from the day before. Example: today is 2018/9/25, I need the data to be taken on 2018/9/24 only. But from my code below, it takes from 23 until 25. Which is more than one day, and it took also two days before from the date I need. I don't know which code that make a wrong result. Anyone can help me with this? I really appreciate it.
Api.js
const TO_DAYS = 4194304 * 1000 * 60 * 60 * 24; // this part that might be the cause
const ROOT_DATE = moment([2018, 3, 30]); // this part that might be the cause
const ROOT_DATE_ID = 440557948108800000; // this part that might be the cause
const DATE_ID = function(date) {
return ROOT_DATE_ID + date.diff(ROOT_DATE, "days") * TO_DAYS;
}; // this part that might be the cause
class discordApi {
constructor() {
this.lock = new AsyncLock();
}
get(momentDate, authorId, offset = 0) {
const url =
config.endpoint +
querystring.stringify({
min_id: DATE_ID(momentDate),
author_id: authorId
});
return fetch(url, {
headers: {
method: "GET",
Authorization: config.auth
}
}).then(res => {
// console.log(res.url);
return res.json();
});
}
async getAllData(momentDate) {
const allData = config.targets.map(author_id =>
this.get(momentDate, author_id)
);
return Promise.all(allData);
}
index.js
var yesterday = moment().subtract(1, "days"); // this part that might be the cause
async function sendEmail() {
const data = await discordApi.getAllData(yesterday);
const unfilteredMessages = data.reduce(
(prev, current) => [...prev, ...current.messages],
[]
);
const filteredMessages = unfilteredMessages.reduce((prev, current) => {
if (prev.length === 0) {
return [...prev, current];
}
const currentConversationIsDuplicated = isConversationDuplicated(
prev[prev.length - 1],
current
);
if (currentConversationIsDuplicated) {
return prev;
}
ret
urn [...prev, current];
}, []);
const convo = await discordApi.AllConvo(filteredMessages);
const mailOptions = {
from: "lala#gmail.com",
to: maillist,
subject: "Discord-Bot Daily Data",
html: convo
};
transporter.sendMail(mailOptions, function(err, info) {
if (err) console.log(err);
else console.log("Message Sent!");
});
}
Related
I need your help, it turns out that I am trying to use the Hubstaff api. I am working on nodejs to make the connection, I followed the documentation (official hubstaff api documentation) and use the methods they give as implementation examples (example of implementation nodejs).
But I get the following error:
I don't know why this happens, and I can't find more examples of how I can implement this api. The openid-client lib is used to make the connection through the token and a state follow-up is carried out to refresh the token.
To be honest, I'm not understanding how to implement it. Can someone who has already used this API give me a little explanation? I attach the code
hubstaffConnect.util
const {
Issuer,
TokenSet
} = require('openid-client');
const fs = require('fs');
const jose = require('jose');
// constants
const ISSUER_EXPIRE_DURATION = 7 * 24 * 60 * 60; // 1 week
const ACCESS_TOKEN_EXPIRATION_FUZZ = 30; // 30 seconds
const ISSUER_DISCOVERY_URL = 'https://account.hubstaff.com';
// API URl with trailing slash
const API_BASE_URL = 'https://api.hubstaff.com/';
let state = {
api_base_url: API_BASE_URL,
issuer_url: ISSUER_DISCOVERY_URL,
issuer: {}, // The issuer discovered configuration
issuer_expires_at: 0,
token: {},
};
let client;
function loadState() {
return fs.readFileSync('./configState.json', 'utf8');
}
function saveState() {
fs.writeFileSync('./configState.json', JSON.stringify(state, null, 2), 'utf8');
console.log('State saved');
}
function unixTimeNow() {
return Date.now() / 1000;
}
async function checkToken() {
if (!state.token.access_token || state.token.expires_at < (unixTimeNow() + ACCESS_TOKEN_EXPIRATION_FUZZ)) {
console.log('Refresh token');
state.token = await client.refresh(state.token);
console.log('Token refreshed');
saveState();
}
}
async function initialize() {
console.log('API Hubstaff API');
let data = loadState();
data = JSON.parse(data);
if (data.issuer) {
state.issuer = new Issuer(data.issuer);
state.issuer_expires_at = data.issuer_expires_at;
}
if (data.token) {
state.token = new TokenSet(data.token);
}
if (data.issuer_url) {
state.issuer_url = data.issuer_url;
}
if (data.api_base_url) {
state.api_base_url = data.api_base_url;
}
if (!state.issuer_expires_at || state.issuer_expires_at < unixTimeNow()) {
console.log('Discovering');
state.issuer = await Issuer.discover(state.issuer_url);
state.issuer_expires_at = unixTimeNow() + ISSUER_EXPIRE_DURATION;
console.log(state.issuer);
}
client = new state.issuer.Client({
// For personal access token we can use PAT/PAT.
// This is only needed because the library requires a client_id where as the API endpoint does not require it
client_id: 'PAT',
client_secret: 'PAT',
});
saveState();
console.log('API Hubstaff initialized');
}
async function request(url, options) {
await checkToken();
let fullUrl = state.api_base_url + url;
return client.requestResource(fullUrl, state.token, options);
}
function tokenDetails() {
let ret = {};
if (state.token.access_token) {
ret.access_token = jose.JWT.decode(state.token.access_token);
}
if (state.token.refresh_token) {
ret.refresh_token = jose.JWT.decode(state.token.refresh_token);
}
return ret;
}
module.exports = {
initialize,
checkToken,
request,
tokenDetails
};
controller
const usersGet = async(req, res = response) => {
const response = await api.request('v2/organizations', {
method: 'GET',
json: true,
});
const body = JSON.parse(response.body);
res.render('organizations', {
title: 'Organization list',
organizations: body.organizations || []
});
};
The problem
I'm still getting used to functional programming (FP). Specially FP in React-native. The goals are:
fetch different characters from the API through iteration
each step returns the percentage completed plus its objects.
the route and its headers may change. (e.g: instead of characters fetch planets instead)
The attempts
Creating separated functions for each step was ok, the problem is how to 'connect' them and get the desired result (as described in 'The Problem' section). Every idea i attempted caused some type of coupling or repetition (of code)
Requests
function requestCharacters(start, token) {
return axios.get(`https://swapi.dev/api/people/${start}/`,{
headers: {
Authorization: 'Bearer ' + token,
ContentType: 'application/json',
}
})
}
function requestPlanets(start) {
return axios.get(`https://swapi.dev/api/planets/${start}/`);
}
Percentage
const percentage = Math.round((start/finish)*100)
Iteration of requests (using recursion)
async function loop(start, finish, callback) {
if (start >= finish) {
console.log("got inside if from loop");
return;
}
await requestCharacters(1)
.then((response) => {
const percentage = Math.round(((start)/finish)*100)
loop(start + 1, finish, callback({ percentage, pageContent: response.data });
})
.catch((error) => console.error(error));
}
loop(1, 3, console.log(percentage, pageContent));
And then some function returning percentage plus object fechted
loop(1, 3, PrintObjectsFromFetch)
How to solve this?
Thanks if you read to the end!
This is the non-refactored version. Hope it helps though
import axios from "axios";
function mountAxiosRequest(url) {
return axios.get(url);
}
const arrayOfPages = (total_pages, baseURL) =>
Array.from({ length: total_pages }, (v, k) =>
baseURL.replace("iterator", k + 1)
);
const total_pages = 16;
const baseURL = "https://swapi.dev/api/people/iterator/";
const arrayOfRequests = (total_pages, baseURL, request) =>
arrayOfPages(total_pages, baseURL).map((url) => request(url));
function PrintPercentageAndData(data) {
console.log("from map percentage: ", data);
}
const mapResponses = (response, total) =>
response.map((row, index) => {
const indexFromOne = index + 1;
const percentage = Math.round((indexFromOne / total) * 100);
return { percentage, data: row };
});
const promiseArray = (arrayOfRequests) => Promise.all(arrayOfRequests);
function GetPercentageAndData(callback, baseURL, request) {
const total_pages = 10;
const requestsArray = arrayOfRequests(total_pages, baseURL, request);
const promissesArray = promiseArray(requestsArray);
promissesArray
.then((results) => {
const result = PrintPercentageAndData(
mapResponses(results, results.length)
);
if (result !== undefined) callback(result);
})
.catch((error) => console.error("error from promissesArray : ", error));
}
GetPercentageAndData(
PrintPercentageAndData,
"https://swapi.dev/api/species/iterator/",
mountAxiosRequest
);
I'm having two issues this moment
I am having trouble displaying the data from my firestore document after the user signs in and they do have a document with data
I have a button that lets the user upload a document and I will parse it to extract all important data. That data is then put into the document with Ids, which is basically the userId + what number doc it is belonging to the user. When they upload the data it seems that all data extracted uses the same ID and only the last one extracted gets displayed.
this is my code:
const loansRef = firebase.firestore().collection('goals');
const [ courseGoals, setCourseGoals ] = useState([]);
const [goalCounter, setGoalCounter] = useState(0)
//let the user upload doc, what gets called when they press button
const pickDocument = async () => {
try {
let input = await DocumentPicker.getDocumentAsync({
type: "text/plain",
});
setUserOut(await FileSystem.readAsStringAsync(input.uri));
} catch (error) {
console.log(error);
}
createLoans();
};
//extracts important info and returns array with all info for one loan
const fileParser = () => {
const parsedLoans = [];
var newUserOut = userOut;
if (newUserOut.length == 0) {
return;
}
//remove the grants
var grantPos = newUserOut.search("Grant Type:");
var pos = newUserOut.search("Loan Type:");
//hopefully just the loans now
newUserOut = newUserOut.slice(pos, grantPos);
while (newUserOut.length > 0) {
var lastPos = newUserOut.lastIndexOf("Loan Type:");
parsedLoans.push(newUserOut.slice(lastPos, newUserOut.length));
newUserOut = newUserOut.slice(0, lastPos);
}
//console.log('parsed loans: ' + parsedLoans)
return parsedLoans;
};
//where we actually create loans and get the important data for each loan
const createLoans = () => {
const newLoans = fileParser();
const title= 'Loan Amount:$'
const interest = 'Loan Interest Rate:'
for(let i =0; i < newLoans.length; i++){
let loan = newLoans[i]
let goalTitle=loan.substring(loan.indexOf(title)+title.length,loan.indexOf('Loan Disbursed Amount:'))
//console.log("goalTitle: " + goalTitle)
let interestRate = loan.substring(loan.indexOf(interest)+interest.length,loan.indexOf('Loan Repayment Plan Type'))
//console.log("Interest rate: "+ interestRate)
let years = 0
let paidOff = 0
addGoalHandler(goalTitle,interestRate,years,paidOff)
}
return
};
useEffect(() => {
getPW()
let isMounted = true;
if (isMounted) {
loansRef.doc(userId).onSnapshot(
(docSnapshot) => {
if(!docSnapshot.exists){console.log('doc doesnt exist, start from scratch')}
else{
console.log('loaded successfully '+docSnapshot.data())
setGoalCounter(docSnapshot.data().loans.length)
console.log(goalCounter)
}
},
(error) => {
console.log(error);
}
);
}
return () => {
isMounted = false;
};
}, []);
const addGoalHandler = (goalTitle, interestRate, years, paidOff) => {
//setCourseGoals([...courseGoals, enteredGoal])
setGoalCounter(goalCounter+1)
setCourseGoals((prevGoals) => [
...courseGoals,
{
id:userId.toString() + goalCounter.toString(),
value: goalTitle,
interest: interestRate,
years: years,
paidOff: paidOff
}
]);
addToFB(goalTitle, interestRate,years,paidOff)
//var oldIDS = docIDS
//oldIDS.push(userId.toString() + goalCounter.toString())
//setDocIDS(oldIDS)
setIsAddMode(false);
};
const cancelGoalAdditionHandler = () => {
setIsAddMode(false);
};
const addToFB = async (goalTitle, interestRate, years, paidOff) => {
//adding data to firebase, takes into account if doc exists already
const loadDoc = await loansRef.doc(userId).get()
.then((docSnapshot)=> {
if(docSnapshot.exists){
loansRef.doc(userId).onSnapshot((docu)=>{
const updateLoansArr = loansRef.doc(userId).update({
loans: firebase.firestore.FieldValue.arrayUnion({
id: userId+goalCounter.toString(),
value: goalTitle,
interest: interestRate,
years: years,
paidOff: paidOff
})
})
//setGoalCounter(goalCounter+1)
})
}
else{
const addDoc = loansRef.doc(userId).set({
loans: firebase.firestore.FieldValue.arrayUnion({
id: userId+goalCounter.toString(),
value: goalTitle,
interest: interestRate,
years: years,
paidOff: paidOff
})
})
//setGoalCounter(goalCounter+1)
}})
//setGoalCounter(goalCounter+1)
}
const removeGoalHandler = async (goalId) => {
/*
setCourseGoals((currentGoals) => {
loansRef.doc(goalId).delete().then(console.log('removed correctly'))
return currentGoals.filter((goal) => goal.id !== goalId);
});
setGoalCounter(goalCounter-1)
*/
//need to use the value and not the goalId
const removeGoal = await loansRef.doc(goalId).update({
goals: firebase.firestore.FieldValue.arrayRemove(goalId)
})
setCourseGoals((currentGoals)=> {
return currentGoals.filer((goal)=> goal.id !== goalId)
})
};
I'm changing the question cause I think I explain myself wrong.
I'm using currently 1 API endpoint to receive data which I need. I need to add a second end point to receive data from both end points in the same time, merge them together and store in Database.
First endpoint -
https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=30m&limit=1
Second endpoint - https://api.binance.com/api/v3/ticker/24hr?symbol=${symbol}
Here is how I receive Data from first endpoint
const getBTCData = async symbol => {
let data = await fetch(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=30m&limit=1`).then(res => res.json());
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Timespan: 30,
}
});
console.log(btcusdtdata);
saveToDatebase(symbol, btcusdtdata);
};
Im returning 4 parameters from this endpoint
And I need to take one parameter from second endpoint and combine it with parameters from first one.
I need this parameter from second endpoint - "quoteVolume": "15.30000000"
I founded that Promise.all can be a solution but I don't understand it properly on how I can return data from 2 api and merge them together in a single object to save in MongoDB.
FULL CODE
Small explanation - goal is to take data from both endpoints and store it in MongoDB as well as calculating the average for quoteVolume on last 200 days.
const { MongoClient } = require('mongodb');
const schedule = require('node-schedule');
const fetch = require("node-fetch");
require('dotenv').config()
"use strict"; // This is ES6 specific. Help's to run code faster(IMPORTANT FOR NOTIFICATION SYSTEM)
const nodemailer = require("nodemailer");
const symbols = ["ADABTC", "AEBTC","AIONBTC"];
//a descriptive name helps your future self and others understand code easier
const getBTCData = async symbol => {
let data = await fetch(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=30m&limit=1`).then(res => res.json());
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5]),
Timespan: 30,
}
});
console.log(btcusdtdata);
saveToDatebase(symbol, btcusdtdata);
//recursive functions are complicated, we can get rid of it here
//by moving the responsibility to the caller
};
//helper function for an awaitable timeout
const sleep = ms => new Promise(res => setTimeout(res, ms));
const j = schedule.scheduleJob('* * * * * *', async() => {
//expand this function to be responsible for looping the data
for (let symbol of symbols) {
await getBTCData(symbol);
await sleep(8000);
}
});
const getDateTime = () => {
let today = new Date();
let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
let time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
return date + ' ' + time;
};
const saveToDatebase = async(symbol, BTCdata) => {
try {
const url = 'mongodb://username:password#ip.adress.com:port/dbname?retryWrites=true&w=majority';
let dateTime = getDateTime();
let db = await MongoClient.connect(url, { useUnifiedTopology: true });
const dbo = db.db('Crypto');
const myobj = Object.assign({ Name: symbol, Date: dateTime }, BTCdata[0]);
await dbo.collection(symbol).insertOne(myobj);
const average = await dbo.collection(symbol).aggregate([{
$addFields: {
DateObj: {
$regexFindAll: { input: "$Date", regex: "\\d+" }
}
}
},
{
$set: {
DateObj: {
$dateFromParts: {
year: { $toInt: { $arrayElemAt: ["$DateObj.match", 0] } },
month: { $toInt: { $arrayElemAt: ["$DateObj.match", 1] } },
day: { $toInt: { $arrayElemAt: ["$DateObj.match", 2] } },
hour: { $toInt: { $arrayElemAt: ["$DateObj.match", 3] } },
minute: { $toInt: { $arrayElemAt: ["$DateObj.match", 4] } },
second: { $toInt: { $arrayElemAt: ["$DateObj.match", 5] } },
timezone: "Europe/London"
}
}
}
},
{
$match: {
$expr: {
$gte: ["$DateObj", { $subtract: ["$$NOW", 201 * 60 * 60 * 24 * 1000] }]
}
}
},
{
"$group": {
_id: null,
"Volume": {
"$avg": "$Volume"
}
}
}
]).toArray();
console.log('1 document inserted');
console.log(BTCdata[0].Volume);
console.log(average[0].Volume);
const RealTimeDataVolume = parseInt(BTCdata[0].Volume);
const HistoricalTimeDataVolume = parseInt(average[0].Volume); // 201 DAYS VOLUME HERE 3286033.4285714286
const DayTimesRealAverage = RealTimeDataVolume * 48; // 1 DAY REAL TIME DATA HERE 196579344
const Previous200dVolume = (HistoricalTimeDataVolume - DayTimesRealAverage) / 200;
const MultiplePrevious200dVolume = Previous200dVolume * 5;
if (MultiplePrevious200dVolume < DayTimesRealAverage) {
async function main() {
let transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true, // true for 465, false for other ports
auth: {
user: process.env.DB_USER, // OUR ALARM EMAIL
pass: process.env.DB_PASS, // OUR ALARM PASSWORD
},
});
let info = await transporter.sendMail({
from: process.env.DB_USER, // sender address
to: process.env.DB_RECEIVER, // list of receivers
subject: symbol + 'Is UP', // Subject line
text: symbol + " IS UP", // plain text body
});
console.log("Message sent: %s", info.messageId, symbol);
}
main().catch(console.error);
} else {
console.log('false');
}
console.log(DayTimesRealAverage);
console.log(MultiplePrevious200dVolume);
} catch (e) {
console.error(e)
}
};
You can do it in the same way.
In response you are getting a son object.
You need to do res["quoteVolume"] to get the data.
I am hitting the google calendar api, and I have a lambda setup in a async try catch. I have tried adding await to every function, tried moving the return to after the if(err) but that gives me a 500. What I need to do is pass the array data from the google calendar api function to the message so I can get it in my front end. Here is the lambda so far. Any help would be greatly appreciated. Thanks
const { google } = require("googleapis")
const { OAuth2 } = google.auth
const faunadb = require("faunadb") /* Import faunaDB sdk */
// Docs on event and context https://www.netlify.com/docs/functions/#the-handler-method
exports.handler = async (event, context) => {
try {
const OAuth2Client = new OAuth2(
"FDSAF",
"FDSAF"
)
// Connect to the database
const q = faunadb.query
const client = new faunadb.Client({
secret: "FDSAFA",
})
let refreshToken
await client
.query(q.Get(q.Ref(q.Collection("AuthUrl"), "fdsa")))
.then(ret => (refreshToken = ret.data.title.refresh_token))
console.log(refreshToken)
OAuth2Client.setCredentials({
refresh_token: refreshToken,
})
// Create a new calender instance.
const calendar = google.calendar({ version: "v3", auth: OAuth2Client })
let ok
function listEvents(callback) {
let array = []
calendar.events.list(
{
calendarId: "primary",
// timeMin: new Date().toISOString(),
maxResults: 100000,
singleEvents: true,
orderBy: "startTime",
},
(err, res) => {
if (err) return console.log("The API returned an error: " + err)
var date = new Date()
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1)
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0)
//console.log(res.data.items)
const events = res.data.items
if (events.length) {
// console.log("Upcoming 10 events:")
events.map((event, i) => {
const start = new Date(event.start.dateTime || event.start.date)
const end = new Date(event.end.dateTime || event.end.date)
if (start >= firstDay && end <= lastDay) {
console.log(start, end, event.summary)
//ok = "test"
array.push(start)
callback(array)
}
// const start = event.start.dateTime || event.start.date
// console.log(`${start} - ${event.summary}`)
})
} else {
console.log("No upcoming events found.")
}
}
)
}
let array
listEvents(function (eventList) {
array = eventList
})
return {
statusCode: 200,
body: JSON.stringify({ message: array }),
// // more keys you can return:
// headers: { "headerName": "headerValue", ... },
// isBase64Encoded: true,
}
} catch (err) {
return { statusCode: 500, body: err.toString() }
}
}
This is the fetch I am doing for it on the front end and it returns an empty object
const IndexPage = () => {
fetch("/functions/list-calendar")
.then(response => response.json())
.then(response => {
console.log(response)
})
It looks to me that you're returning your response before the callback has been executed. If you're not familiar with async and await, you should read this documentation. Basically you need to wait for the callback to happen before you return, and you can either do this using callback functions, .then chains or async functions.
I also noticed in your code that you're calling the callback everytime you're doing a push into array. I think that it's simpler to push all your items into array and then callback the array.
Rather than do a push in the map (which is confusing), this returns a new array of event.start.dateTime and because if (start >= firstDay && end <= lastDay) is false, it adds a null to the array, so .filter(x => Boolean(x)); filters them out so you just get an array of datetimes.
let array = events.map((event, i) => {
const start = new Date(event.start.dateTime || event.start.date)
const end = new Date(event.end.dateTime || event.end.date)
if (start >= firstDay && end <= lastDay) {
return start;
else
return null;
// const start = event.start.dateTime || event.start.date
// console.log(`${start} - ${event.summary}`)
})
.filter(x => Boolean(x));
Simple Version
You could move your return into the callback.
listEvents(function (eventList) {
array = eventList;
return {
statusCode: 200,
body: JSON.stringify({ message: array }),
// // more keys you can return:
// headers: { "headerName": "headerValue", ... },
// isBase64Encoded: true,
}
});
Promise Version
My node is a bit rusty but you could change your method to return a promise.
function listEvents(callback) {
return new Promise((resolve, reject) => {
calendar.events.list(
{
calendarId: "primary",
// timeMin: new Date().toISOString(),
maxResults: 100000,
singleEvents: true,
orderBy: "startTime",
},
(err, res) => {
if (err) reject("The API returned an error: " + err));
var date = new Date()
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1)
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0)
//console.log(res.data.items)
const events = res.data.items
if (events.length) {
// console.log("Upcoming 10 events:")
let array = events.map((event, i) => {
const start = new Date(event.start.dateTime || event.start.date)
const end = new Date(event.end.dateTime || event.end.date)
if (start >= firstDay && end <= lastDay) {
return start;
else
return null;
// const start = event.start.dateTime || event.start.date
// console.log(`${start} - ${event.summary}`)
}).filter(x => Boolean(x));
resolve(array);
} else {
resolve([]);
}
})
});
}
and then, since you're already using async,
let array = await listEvents();
Updated Version
If you want to return array data in a different format.
let array = events.filter(event => {
const start = new Date(event.start.dateTime || event.start.date)
const end = new Date(event.end.dateTime || event.end.date)
if (start >= firstDay && end <= lastDay) {
return true;
else
return false;
})
.map(event => {
startDate: new Date(event.start.dateTime || event.start.date),
endDate: new Date(event.end.dateTime || event.end.date),
summary: event.summary
});
If you want to group by a property, you can search StackOverflow for answers, like this one: Most efficient method to groupby on an array of objects, the below groupByArray function was taken from the comments on the accepted answer.
function groupByArray(xs, key) { return xs.reduce(function (rv, x) { let v = key instanceof Function ? key(x) : x[key]; let el = rv.find((r) => r && r.key === v); if (el) { el.values.push(x); } else { rv.push({ key: v, values: [x] }); } return rv; }, []); }
let groupedAndFilteredEvents = groupByArray(events.filter(event => {
const start = new Date(event.start.dateTime || event.start.date)
const end = new Date(event.end.dateTime || event.end.date)
if (start >= firstDay && end <= lastDay) {
return true;
else
return false;
})
.map(event => {
event.groupByKey = event.start.dateTime;
return event;
}), "groupByKey");