Pull Gmails into a Google Sheet - javascript

This script works brilliantly to pull emails into my sheet. My problem is that the function only pulls the first two fields listed. e.g., getPlainBody, getSubject - even though more fields are asked for. So instead of having one function that pulls all the fields I need (getPlainBody, getSubject, getTo, getDate, getFrom) I only get the first two (getPlainBody, getSubject). Is there an obvious modification that will pull all 5 fields into the sheet?
function getEmails_(q) {
sh0.clear();
var emails = [];
var threads = GmailApp.search(q);
for (var i in threads) {
var msgs = threads[i].getMessages();
for (var j in msgs) {
emails.push([msgs[j].getPlainBody(), [msgs[j].getSubject(), [msgs[j].getDate(), [msgs[j].getTo(), [msgs[j].getFrom()
]]]]]);
}
}
return emails;
}
function appendData_(sh0, array2d) {
sh0.getRange(sh0.getLastRow() + 1, 1, array2d.length, array2d[0].length).setValues(array2d);
}
function saveEmails() {
var array2d = getEmails_(SEARCH_QUERY);
if (array2d) {
appendData_(sh0, array2d);
}}

Your code is fine the problem is how you are constructing the 2D array.
in the .push() method, your use of the square brackets - [] - is building an array within an array within another array within another array within another array within another array, it's easier to see it in the screenshot below.
What you need is 1 array of horizontals cells with an array of vertical rows.
So change:
emails.push([msgs[j].getPlainBody(), [msgs[j].getSubject(), [msgs[j].getDate(), [msgs[j].getTo(), [msgs[j].getFrom()]]]]]);
to
emails.push([msgs[j].getPlainBody(), msgs[j].getSubject(), msgs[j].getDate(), msgs[j].getTo(), msgs[j].getFrom()]);
On a personal note, I usually always format the date to something a little more readable. You can use Utilities to do this. Ex: format: Thu Jun 15 2017 11:18:18 GMT+0700 (ICT) to 15/06/2017 # 11:18
var formatDate = Utilities.formatDate(emails[i][2], 'GMT+07:00', 'dd/MM/yyyy # HH:mm')

Related

A loop but selective numbers

I have to retrieve data from an API.
Certain data has to be retrieved in a certain order.
To be exact, data needs to be retrieved in this order:
7,40,8,9,10,45,11,39,5,12,13,15,6,18,0,46,22,23,3,41,1,24,42,25,26,4,27,2
So when loop is doing 0, then it needs to retrieve data number 7, when loop is doing 1, then data number 40 and if loop is doing 2 then data number 8 etc.
listWithDataFromAPI I do this:
metricsSheet.appendRow([listWithDataFromAPI.symbols]);
And get this response:
[Ljava.lang.Object;#1e1aaea2
When I insert a specific number I do this:
metricsSheet.appendRow([listWithDataFromAPI.symbols].symbols[8]]);
And get such response: {name=DataPeter, longVolume=6640.87, longPositions=23678}
Thus if loop is 0 then extract 7, loop is 2 extract 40 etc. as I mentioned.
This is what I'm trying in concept:
var listNumberValue = ["5","30","7"];
var symbols = listWithDataFromAPI.symbols;
for (var i in listNumberValue) {
var symbol = symbols[listNumberValue];
metricsSheet.appendRow([symbol.name]);
}
Hope this makes sense.
Not sure how to do this..?
The big problem for us is that we don't know what listWithDataFromAPI is and you have not explained it. But I think you're trying to say that you want to iterate over something that you can get from it so I took a stab at what I think you're trying to do.
The first function will take your 0 through 46 indexes and reorder as 7,40,8,9,10,45,11,39,5,12,13,15,6,18,0,46,22,23,3,41,1,24,42,25,26,4,27,2
As shown in this table.
function getIdxObj() {
var idxA=[7,40,8,9,10,45,11,39,5,12,13,15,6,18,0,46,22,23,3,41,1,24,42,25,26,4,27,2];
var idxObj={};
for(var i=0;i<idxA.length;i++) {
idxObj[i]=idxA[i];
}
return idxObj;
}
The second function loops over symbols which apparently come from listWithDataFromAPI.symbols which has not been explained and so we know nothing about it.
function theUnknownFunction() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('metrics');//not sure about this either
var idxObj=getIdxObj();
var symbols = listWithDataFromAPI.symbols; //I dont have a clue as to what listWithDataFromAPI is
for (var i=0;i<symbols.length;i++) {
var symbol = symbols[idxObj[i]];
sh.appendRow([symbol.name]);
}
}

Angularjs - match a date from an array of dates to find the closest match to display in a dropdown

Hi please see my plunkr below
https://plnkr.co/edit/8cJZsb?p=preview
I have $scope.data which looks like this
$scope.data = [
{
"projectedStart":"2017-01-20T00:00:00"
},
{
"projectedStart":"2017-02-09T00:00:00"
}
];
and $scope.possibleDates that look like this
$scope.possibleDates = [{
"projectedStartDate":"2017-01-25T00:00:00",
"dateName":"January - Week 4 (20/10)"
},
{
"projectedStartDate":"2017-02-01T00:00:00",
"dateName":"February (6/10)"
},
{
"projectedStartDate":"2017-03-01T00:00:00",
"dateName":"March (0/2)"
},
{
"projectedStartDate":"2017-04-05T00:00:00",
"dateName":"April (2/5)"
}]
On the front end dropdown list, I want to be able to display the possibleDates that match closest to the 'projectedStart' date in $scope.data.
I am thinking of doing an angular foreach and looping through each projectedStart date in $scope.data and somehow compare it with each of the dates in $scope.possibleDates and updating $scope.Data's projectedStart with the closest match? Failing miserably so far.
Would greatly appreciate it if someone could point me in the right direction
Look's like you need to look into moment.js. It's a spectacular library for date parsing, formatting, and comparison.
You could put a watcher on possibleDates, and when they change you compute the list that you are after.
The list can be easily written with tools like moment and underscore.
const projectedDate = moment($scope.data[0].projectedStartDate);
const sortedPossibleDates = _.chain($scope.possibleDates)
.each((possibleDate) => {
possibleDate.diff = projectedDate.difference('seconds');
});
.sortBy('diff')
.value()
And voila, the sortedPossibleDates[0] is your best answer
A basic sort function should be able to order the possible dates by how close they are to the chosen start date. Just use new Date(ISOString) to get the numerical timestamps.
From: https://stackoverflow.com/a/11796365/6452040
If you put a function in script.js like this, which finds the closest date (before or after):
$scope.closestStartDate = function(startDate) {
var smallestDifferenceInDates = 1000000000000;//impossibly large value
var closestDateName = 'tmp';
var date = new Date(startDate);
for (var i = 0; i < Object.keys($scope.possibleDates).length; i++) {
var projectedDate = new Date($scope.possibleDates[i].projectedStartDate);
if (Math.abs(date.getTime() - projectedDate.getTime()) < smallestDifferenceInDates) {
smallestDifferenceInDates = Math.abs(date.getTime() - projectedDate.getTime());
closestDateName = $scope.possibleDates[i].dateName;
}
}
return closestDateName;
}
Then change your template code to this:
<tr ng-repeat="d in data">
<td>
{{ closestStartDate(d.projectedStart) }}
</td>
</tr>
You'll get the closest date from $scope.possibleDates (Math.abs() gets the distance between the two, if you want dates after you can leave that off).

Separate data from text file using Javascript

I'm working on creating an analytics page that uses data stored in a text file. The text file is used for my highcharts graph and is separated like so:
November 7th 6AM,19.8
November 7th 6PM,19.8
November 8th 6AM,20.4
November 8th 6PM,14.6
November 9th 6AM,15.9
November 9th 6PM,15.1
November 10th 6AM,16.4
November 10th 6PM,16.4
I'm looking to separate that data into 12 calendar panes that will display overall discrepancies for each month. For example, if a date had the value 16, and then it dropped to 10 the next reading, to take a cumulative sum for how many times that happened for the month.
How do I make sure that it reads from the text file in proper order and that it checks to see if the next value went below 10 and tallies that somewhere?
Yo can use jQuery to separate the file data into array.
$(document).ready(function() {
//fetch text file
$.get('text.txt', function(data) {
//split on new lines
var lines = data.split('\n');
for(var i=0;i<lines.length;i++) {
// use lines[i] the way you want
}
});
});
Then you can use this to get sub-strings:
var a = s.indexOf(',');
var b = s.substring(a,4);
This way you can separate the data and use it as desired.
You need to
Fetch the data file
One usually does this with AJAX (XMLHttpRequest)
Separate your datapoints
Your data seems to be neat enough that you can, for every line in the file, get the name of the month with line.split(" ")[0] and the value with line.split(",")[1]. Splitting a text to lines can usually be as easy as text.split("\n").
Iterate over results
For every month-value pair you now have, compare the name of the months. If it is a match and the value has changed by x, increment a value in your books, e.g. discrepancies[monthName]++. Save the name-value pair and continue.
Example:
// Get the data
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) { // If the request is complete with status code "OK"
handleImportantData(req.responseText);
}
};
// Define the request to be using the method GET to an URL asynchronously.
req.open("GET", "important_data.txt", true);
req.send();
function handleImportantData(data) {
var treshold = 5.0;
var months = {};
var discrepancies = {};
// Separate data points.
var lines = data.split("\n");
lines.forEach(function(line) {
// The || 0.0 part sets the value to zero if our data is malformed.
// We parse the value as a float to prevent it being saved as a string,
// which would make arithmetic operations on it not work as expected.
months[line.split(" ")[0]] = parseFloat(line.split(",")[1]) || 0.0;
});
// Find discrepancies.
var previous = {
name: "",
value: 0.0
};
for (var name in months) {
// If not already there, initialize the data point with ternary operation including NOP.
discrepancies[name] ? {} : discrepancies[name] = 0.0;
// If we're still talking about the same month as before and the value
// has changed for more than our treshold, save it as a discrepancy.
if name === previous.name && Math.abs(previous.value - months[name]) > treshold {
discrepancies[name] ++;
}
previous = {
name: name,
value: months[name]
}; // Set this as the previous value.
}
// Here we have ready discrepancy data stored in the variable discrepancies.
}

JS If variable matches csv value push to array

Im trying accept user input and then if it matches the first value in a row of my csv push that entire row to an array.
I have a csv that looks like this.
City,Lat,Lon,Date
Seattle,47.6,122.3,2015 06 03
Spokane, 47.65, 117.42,2015 06 04
I accept user input like this.
var city = window.prompt("Which city are looking for",);
console.log(city);
Then if the city the user entered matches a city in the csv I want to push it to a new array. Here is the code I wrote for it, but its not quite working.
d3.csv("./some.csv", function(data) {
var lst = [];
for (var i = 0; i < data.length; i++){
if (data.City[i] == 'city') {
lst.push(data[i]);
}
console.log(lst);
}
});
My desired output would look something like this.
[['Seattle',47.6,122.3,2015 06 03],
['Seattle',47.6,122.3,2015 06 05]]
Any suggestions would be greatly appreciated.
I can see several problems.
if (data.City[i] == 'city') {
data is an array, each entry of which is an object with properties with the same names as the column heads. So, instead of data.City[i] you want data[i].City.
Also you are comparing the result with the string literal 'city' instead of the variable city.
Finally you should probably use === to avoid confusing results.
So this line should probably read:
if (data[i].City === city) {
The other thing is the data structure returned by D3 does not match what you are expecting. Instead of:
[['Seattle',47.6,122.3,2015 06 03]]
you will get
[ { City: 'Seattle', Lat: 47.6, Lon: 122.3, Date: '2015 06 03' } ]
If that is a problem for you, you could consider using the d3.csv.parseRows method which returns the data in the form you are expecting. In that case you will need to adapt the comparison line accordingly.

How do i reverse JSON in JavaScript?

[
{"task":"test","created":"/Date(1291676980607)/"},
{"task":"One More Big Test","created":"/Date(1291677246057)/"},
{"task":"New Task","created":"/Date(1291747764564)/"}
]
I looked on here, and someone had the same sort of question, but the "checked" correct answer was that it will be different on IE if the item is deleted, which would be fine. My issue is, those items above are stored, but when i go and grab them, iterate, and return, the items are reversed and the created is at the 0 index and task is at 1. Also, i need to return this as JSON.
Here is my basic JS (value == an int the user is passing in):
outputJSON = {};
for(x in json[value]){
outputJSON[x] = _objectRevival(json[value][x]);
}
return outputJSON;
That returns:
created: Mon Dec 06 2010 15:09:40 GMT-0800 (Pacific Standard Time)
task: "test"
The order of the properties of an object is undefined. It is not possible to force them in a specified order. If you need them in a specific order, you can build this structure reliably using arrays:
var values = [
[["task", "test"], ["created", "/Date(1291676980607)/"]],
[["task", "One More Big Test"], ["created", "/Date(1291677246057)/"]],
[["task", "New Task"], ["created", "/Date(1291747764564)/"]]
];
Then you can iterate over your structure like this:
for (var i = 0; i < values.length; i++) {
for (var k = 0; k < values[i]; k++) {
// values[i][k][0] contains the label (index 0)
// values[i][k][1] contains the value (index 1)
}
}
To enforce a particular order for your output just replace json[value] in your for loop with an array of the object properties in the order you want to display them, in your case ["task", "created"].
The problem is that javascript objects don't store their properties in a specific order. Arrays on the other do (hence why you can get something consistent from json[0], json[1], json[2]).
If your objects will always have "task" and "created", then you can get at them in any order you want.
json[value]["task"]
and
json[value]["created"]
Update:
This should work with your existing code.
Before sending the json object:
var before = [
{"task":"test","created":"/Date(1291676980607)/"},
{"task":"One More Big Test","created":"/Date(1291677246057)/"},
{"task":"New Task","created":"/Date(1291747764564)/"}
];
var order = [];
for (var name in before[0]) {
order.push(name); // puts "task", then "created" into order (for this example)
}
Then send your json off to the server. Later when you get the data back from the server:
var outputJSON = {};
for (var x in order) {
if (order.hasOwnProperty(x)) {
outputJSON[order[x]] = _objectRevival(json[value][order[x]]); // I'm not sure what _objectRevival is...do you need it?
}
}
return outputJSON;
var items = ["bag", "book", "pen", "car"];
items.reverse();
This will result in the following output:
car , pen, book, bag
Even if you have JSON array it will reverse.

Categories

Resources