Google App Script. JSON from BigQuery.Jobs.query response - google-apps-script

I want to get JSON string from a response of BigQuery.Jobs.query. Are there any easy ways?
Google App Script
var request = {
query: 'SELECT TOP(word, 300) AS word, COUNT(*) AS word_count ' + 'FROM publicdata:samples.shakespeare WHERE LENGTH(word) > 10;'
};
var queryResults = BigQuery.Jobs.query(request, projectId);
What I want to take a JSON text from queryResults
[
{
"word": "counterfeit",
"word_count": "28"
},
{
"word": "remembrance",
"word_count": "24"
},
{
"word": "countenance",
"word_count": "24"
},
It worked thanks to Henrique Abreu.
var request = {
query: 'SELECT TOP(word, 300) AS word, COUNT(*) AS word_count ' + 'FROM publicdata:samples.shakespeare WHERE LENGTH(word) > 10;'
};
var queryResults = BigQuery.Jobs.query(request, projectId);
Logger.log(parseSimpleResults(queryResults));
[
{
word_count=28,
word=counterfeit
},
{
word_count=24,
word=remembrance
}
]

I have not tested this with more BigQuery query results, but it should work fine for "simple" results.
function parseSimpleResults(results) {
var names = results.schema.fields.map(function(field){ return field.name; });
return results.rows.map(function(row) {
var obj = {};
for( var i = 0, len = names.length; i < len; ++i ) {
obj[names[i]] = row.f[i].v;
}
return obj;
});
}
Just pass your queryResults variable to it and you should get your nice array of objects.

just one of directions for you to explore:
local obj = JSON.parse(queryResults)
return obj.rows[1].f[1].v, obj.rows[1].f[2].v

Related

Delete token from SAPUI5 Multi Input Field with Data Binding

in my SAPUI5 app I am using a Multi Input Field with tokens which are bound to a JSON Model. Newly added entries are saved in the JSON Model. However, when deleting a token by pressing the "x" next to the token text, the token disappears from the multi input field. But when adding a new token the deleted one reappears.
How can I ensure that the deleted entry is also deleted from the JSON Model?
This is my current code for adding the token to the model:
multiInputField.addValidator(function(args){
MessageBox.confirm("Do you really want to add Token\"" + args.text + "\"?", {
onClose: function(oAction) {
if (oAction === MessageBox.Action.OK){
var oToken = new Token({key: args.text, text: args.text});
args.asyncCallback(oToken);
var aFields = sap.ui.getCore().getView().getModel("myModel").getProperty("/Tokens");
var oNewFields= {
Tokens: args.text
};
aFields .push(oNewFields);
sap.ui.getCore().getView().getModel("myModel").setProperty("/Tokens", aFields );
sap.ui.getCore().getView().getModel("myModel").refresh();
} else {
args.asyncCallback(null);
}
},
title: "Add Token"
});
return sap.m.MultiInput.WaitForAsyncValidation;
});
I guess we can use "tokenUpdate" event for this.
For example, given that I have this MultiInput in my view:
<MultiInput width="500px" id="multiInput" suggestionItems="{ path: 'dataModel>/data'}" showValueHelp="true" tokenUpdate="onTokenUpdate">
<core:Item key="{dataModel>key}" text="{dataModel>value}"/>
</MultiInput>
then in my controller I can handle this like :
onTokenUpdate: function(oEvent) {
var sType = oEvent.getParameter("type");
if (sType === "removed") {
var sKey = oEvent.getParameter("removedTokens")[0].getProperty("key");
var oModel = this.getView().getModel("dataModel");
var aData = this.getView().getModel("dataModel").getProperty("/data");
for (var i = 0, len = aData.length; i < len; i++) {
var idx;
console.log(sKey + "-" + aData[i].key);
if (aData[i].key === sKey) {
idx = i;
}
}
aData.splice(idx, 1);
oModel.setProperty("/data", aData);
console.log(oModel);
}
}
And this is my json:
{
"data": [
{
"key": "token1",
"value": "token1"
},
{
"key": "token2",
"value": "token2"
}
]
}

telegram bot keyboard with google apps script

I want to meet new clients in telegram bot with a keyboard buttons
So far I have this code written in Google Apps Script, but in result there is nothing.
function doPost(e) {
var API_TOKEN = 'bla-bla-bla';
var update = JSON.parse(e.postData.contents);
if (update.hasOwnProperty('message')) {
var msg = update.message;
var chatId = msg.chat.id;
if (msg.text == '/start') {
function sendText(chatId, text, keyboard) {
var payload = {
'method': 'sendMessage',
'chat_id': String(chatId),
'text': "Hello",
'parse_mode': 'HTML',
reply_markup: JSON.stringify({
keyboard: [
[
"A",
"B"
],
[
"C",
"D"
]
],
resize_keyboard: true,
one_time_keyboard:true
})
}
var data = {
"method": "post",
"payload": payload
}
UrlFetchApp.fetch('https://api.telegram.org/bot' + API_TOKEN + '/', data);
}
}
}
}
Is this a missing feature or it's me, doing something wrong?
You probably want something like this?
PS: replace it with your chat id
function testKeyboard() {
const chatId = YOURCHATID; // REPLACE THIS
const choices = ['Mozzarella','Gouda cheese','Camembert','Gorgonzola','Cheddar Cheese'];
const text = 'Make your choice';
sendKeyboard(chatId, choices, text);
}
You can do it with this code.
PS: replace token with your bot's token
const token = ''; // REPLACE IT WITH YOUR BOTS TOKEN
const telegramApi = 'https://api.telegram.org/bot' + token;
function sendKeyboard(chatId, choices, text = 'Menu') {
const buttons = transformArrayToKeyboard(choices);
const replyKeyboardMarkup = {keyboard: buttons,
one_time_keyboard: true,
resize_keyboard: true};
const replyMarkup = JSON.stringify(replyKeyboardMarkup);
const url = telegramApi + '/sendMessage?chat_id=' + encodeURIComponent(chatId) + '&text=' + encodeURIComponent(text) + '&disable_web_page_preview=true&reply_markup=' + encodeURIComponent(replyMarkup);
const response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function transformArrayToKeyboard(choices) {
const maxLengthRowKeyboardMenu = 3;
const arr = choices.map(item => ({text: item }));
const result = [];
let index = 0;
while(arr.slice(index).length > 0) {
const newRowValuesForButtons = arr.slice(index,index+maxLengthRowKeyboardMenu);
result.push(newRowValuesForButtons);
index += maxLengthRowKeyboardMenu;
}
return result;
}
// function transformArrayToKeyboard transforms [4,5,6,7,8] to:
// [
// [
// {text: "4" },{text: "5" },{text: "6" }
// ]
// [
// {text: "7" },{text: "8" }
// ]
// ];

Selecting a specific node in JSON using Appcelerator Titanium

Hopefully an easy question for you.
I have an API service from Rackspace which I call, recently they changed the order of some of the responses, meaning part of my app would no longer upload images to the correct POST url.
I've put a temp fix in place by hard coding the URL's it should be posting to, but I want to be sure I future proof against any changes in their API ordering or indeed any changes to the URL itself.
So, originally I was using the JSON response and choosing the first node and its children.
var CFtenantID = getRSToken.access.serviceCatalog[0].endpoints[0].tenantId;
var CFregion = getRSToken.access.serviceCatalog[0].endpoints[0].region;
var CFpublicURL = getRSToken.access.serviceCatalog[0].endpoints[0].publicURL;
Now, that node has moved to position 18 in a long list. So, I can manually set the script to retrieve it.
var CFtenantID = getRSToken.access.serviceCatalog[17].endpoints[0].tenantId;
var CFregion = getRSToken.access.serviceCatalog[17].endpoints[0].region;
var CFpublicURL = getRSToken.access.serviceCatalog[17].endpoints[0].publicURL;
What I'd like to be able to do, is scan for the "name" instead and just return the CloudFiles info I need, rather than having to declare an actual number of the array.
Here is a snippet of the JSON response from Rackspace.
{
"name": "cloudFeeds",
"endpoints": [
{
"region": "LON",
"tenantId": "1234",
"publicURL": "https://lon.feeds.api.rackspacecloud.com/1234",
"internalURL": "https://atom.prod.lon3.us.ci.rackspace.net/1234"
}
],
"type": "rax:feeds"
},
{
"name": "cloudFiles",
"endpoints": [
{
"region": "LON",
"tenantId": "MossoCloudFS_xxxxxx",
"publicURL": "https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_xxxxx",
"internalURL": "https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_xxxxx"
}
],
"type": "object-store"
},
{
"name": "cloudFilesCDN",
"endpoints": [
{
"region": "LON",
"tenantId": "MossoCloudFS_xxxxxx",
"publicURL": "https://cdn3.clouddrive.com/v1/MossoCloudFS_xxxxxx"
}
],
"type": "rax:object-cdn"
}
And here is my overall script in Appcelerator.
var authCloudFiles = Ti.Network.createHTTPClient({
onload: function() {
// output
Ti.API.info(this.responseText);
var getRSToken = JSON.parse(this.responseText);
var rsToken = getRSToken.access.token.id;
var rsTenantID = getRSToken.access.token.tenant.id;
var rsTenantName = getRSToken.access.token.tenant.name;
var CFtenantID = getRSToken.access.serviceCatalog[17].endpoints[0].tenantId;
var CFregion = getRSToken.access.serviceCatalog[17].endpoints[0].region;
var CFpublicURL = getRSToken.access.serviceCatalog[17].endpoints[0].publicURL;
var rsUserID = getRSToken.access.user.id;
Ti.App.Properties.setString('rsToken', rsToken);
Ti.App.Properties.setString('rsTenantID', rsTenantID);
Ti.App.Properties.setString('rsTenantName', rsTenantName);
Ti.App.Properties.setString('CFtenantID', CFtenantID);
Ti.App.Properties.setString('CFregion', CFregion);
Ti.App.Properties.setString('CFpublicURL', CFpublicURL);
Ti.App.Properties.setString('rsUserID', rsUserID);
//alert(rsToken);
Ti.API.info('rsToken: ' + rsToken);
Ti.API.info('rsTenantID: ' + rsTenantID);
Ti.API.info('rsTenantName: ' + rsTenantName);
Ti.API.info('CFtenantID: ' + CFtenantID);
Ti.API.info('CFregion: ' + CFregion);
Ti.API.info('CFpublicURL: ' + CFpublicURL);
Ti.API.info('rsUserID: ' + rsUserID);
// then we need to load the next step
rackspaceUpload();
}
});
authCloudFiles.open('POST', 'https://identity.api.rackspacecloud.com/v2.0/tokens');
Can anyone help?
Simon
I have never used Appcelerator Titanium before, but it looks like it is just JavaScript.
You could try replacing the following:
var CFtenantID = getRSToken.access.serviceCatalog[17].endpoints[0].tenantId;
var CFregion = getRSToken.access.serviceCatalog[17].endpoints[0].region;
var CFpublicURL = getRSToken.access.serviceCatalog[17].endpoints[0].publicURL;
with:
var CFtenantID = "";
var CFregion = "";
var CFpublicURL = "";
var catalog = getRSToken.access.serviceCatalog;
for (var i=0; i<catalog.length; i++) {
if (catalog[i].name == "cloudFiles") {
for (var j=0; i<catalog[i].endpoints.length; j++) {
if (catalog[i].endpoints[j].region == "LON") {
CFtenantID = catalog[i].endpoints[j].tenantId;
CFregion = catalog[i].endpoints[j].region;
CFpublicURL = catalog[i].endpoints[j].publicURL;
break;
}
}
}
}
My JavaScript is a little rusty though, you may want to add some additional error handling.

Node.js + bluebird + JSON. JSON is not valid after modification

Trying to get API data.
I have problem with creating valid JSON after modification.
Data should looks like this: [{"1"},{"2"},{"3"}, ... ,{201},{202},{203}, ...]
but now: [{"1"},{"2"},{"3"}, ...],[{"201"},{"202"},{"203"}, ...]
Where is my mistake?
var Promise = require("bluebird");
var request = require('bluebird').promisifyAll(require('request'));
var fs = Promise.promisifyAll(require('fs'));
var ladders = {"hardcore":"hardcore", "standard":"standard"};
function getJSONsync(urls) {
var ladder = [];
Promise.map(urls, function(url) {
return request
.getAsync(url)
.spread(function (res, body) {
if (res.statusCode != 200) {
throw new Error('Unsuccessful attempt. Code: '+ res.statusCode);
}
return JSON.stringify(ladder.concat(JSON.parse(body).entries), "", 4);
})
.catch(console.error);
},{ concurrency: 10 })
.then(function(arr) {
fs.writeFileAsync('file.json', arr);
})
}
function setUrls(ladderName, offset, limit) {
var arr = [];
while(offset < 15000 ) {
arr.push('http://api.pathofexile.com/ladders/'+ladderName+'?offset='+offset+'&limit='+limit);
offset = offset + 200;
}
return arr;
}
getJSONsync(setUrls(ladders.hardcore, 0, 200));
Thx for help.
Sorry for my Eng.
Finally:
var Promise = require("bluebird");
var request = require('bluebird').promisifyAll(require('request'));
var fs = Promise.promisifyAll(require('fs'));
var ladders = {"hardcore":"hardcore","standard":"standard"};
function getJSONsync(urls) {
Promise.map(urls, function(url) {
return request
.getAsync(url)
.spread(function (res, body) {
if (res.statusCode != 200) {
throw new Error('Unsuccessful attempt. Code: '+ res.statusCode);
}
return JSON.parse(body).entries;
})
.catch(console.error);
},{ concurrency: 10 })
.reduce(function(a, b) { return a.concat(b) })
.then(function(arr) {
fs.writeFileAsync('file.json', JSON.stringify(arr, "", 4));
console.log(arr.length);
})
}
function setUrls(ladder, offset, limit) {
var arr = [];
while(offset < 15000 ) {
arr.push('http://api.pathofexile.com/ladders/'+ladder+'?offset='+offset+'&limit='+limit);
offset = offset + 200;
}
return arr;
}
getJSONsync(setUrls(ladders.hardcore, 0, 200));
Promise.map returns an array, so when you do ladder.concat you return another array, so it becomes [[{"1"}], [{"1", "2"}]
You should just remove concat:
return JSON.stringify(JSON.parse(body).entries, "", 4);
But if you want to use variable ladder you may ladder.push(JSON.stringify(JSON.parse(body).entries, "", 4)) and use it instead of arr returned variable

Convert Url/Path to Json with Node.js

I recently built a little node program able to console.log all the files of a precise path.
The result I get from this function looks like this for instance :
/Volumes/TimeCapsule/movies/movie1
movie1.mp4
/Volumes/TimeCapsule/movies/movie2
movie2.mp4
/Volumes/TimeCapsule/movies/movie3
movie3.mp4
Now my question is: how can I manage to convert each of this path to JSON so I could be able for instance to display all the files of the movie folder in a single html page ?
I would like to have something like this :
{ "Volumes": {
"TimeCapsule": {
"Movies":{
"Title": "Movie1"
"Title": "Movie2"
"Title": "Movie3"
}
}
}
}
Thank you in advance.
By the way here is my walk function :
var fs = require('fs');
var walk = function (currentPath) {
console.log(currentPath);
var files = fs.readdirSync(currentPath); //Returns array of filename in currenpath
for (var i in files) {
var currentFile = currentPath + '/' + files[i];
var stats = fs.statSync(currentFile);
if (stats.isFile()) {
console.log(currentFile.replace(/^.*[\\\/]/, '')););
}
else if (stats.isDirectory()) {
walk(currentFile);
}
}
};
OK, here we go:
var fs = require( "fs" );
function walk( path, arr ) {
var ret = {};
arr = Array.isArray( arr ) ? arr : [];
fs.readdirSync( path ).forEach(function( item ) {
var current = path + "/" + item;
var stats = fs.statSync( current );
if ( stats.isFile() ) {
arr.push( current );
} else if ( stats.isDirectory() ) {
walk( current, arr );
}
});
arr.forEach(function( item ) {
var i, len;
item.split( "/" ).reduce(function( obj, path, i, parts ) {
if ( ( i + 1 ) === parts.length ) {
obj.Title = path;
} else {
obj[ path ] = obj[ path ] || {};
return obj[ path ];
}
}, ret);
});
return ret;
}
this was not tested, but maybe it give you some ideas on how to do it.
Here is what I really wanted, I even added a path section so I can have an access to the path of each single file :
var fs = require('fs'),
path = require('mypath')
function walk(path) {
var stats = fs.lstatSync(mypath),
info = {
path: mypath,
Title: path.basename(mypath)
};
if (stats.isDirectory()) {
info.type = "folder";
info.children = fs.readdirSync(filename).map(function(child) {
return walk(mypath + '/' + child);
});
} else {
info.type = "file";
}
return info;
}
console.log(walk('/Users/maximeheckel/Desktop'));
Thank you for your help.