applying mulitlevel json to endpoint response - javascript

I have the following code deployed as web app on google sheets
function doGet(e){
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/sskey/edit#gid=0");
var sheet = ss.getSheetByName("TV_Series");
return getData(sheet);
}
function getData(sheet){
var jo = {};
var dataArray = [];
var rows = sheet.getRange(2,1,sheet.getLastRow()-1, sheet.getLastColumn()).getValues();
Logger.log("rows = "+rows);
for(var i = 0, l= rows.length; i<l ; i++){
var dataRow = rows[i];
Logger.log("i ="+i);
Logger.log("dataRoes = " +dataRow);
var record = {};
record['series_name'] = dataRow[0];
record['season_name'] = dataRow[1];
record["season_number"] = dataRow[2];
record["episode_name"] = dataRow[3];
record["episode_number"] = dataRow[4];
record["media_url"] = dataRow[8];
dataArray.push(record);
}
jo.series = dataArray;
var result = JSON.stringify(jo);
return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}
So the web app url returns the following JSON:
{"series":
[{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"Glue","episode_number":"1","media_url":"https://someurl.net/path"},
{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"New Rules","episode_number":"2","media_url":"https://someurl.net/path"}]}
i would like to separate series, seasons, and episodes to different objects in the JSON file. So i will get something like that:
{
"series":{"name": "Dance Academy",
"seasons":
[{"name":"season 1","season_number":1,"episodes":
[{"name":"episode 1","episode_number":1,"url":"https://someurl.net/path"},
{"name":"episode 2","episode_number":2,"url":"https://someurl.net/path"}]},
{"name": "season 2", "season_number":2,"episodes":
[{"name":"episode 1","episode_number":1,"url":"https://someurl.net/path"},
{"name":"episode 2","episode_number":2,"url":"https://someurl.net/path"}]}]}}
How do i do that?
thanks

Description
This assumes there is only one "series". Here is an example script to build a multilevel object from the sample json. You have to build the first object outside of any loop so that you have something to compare with inside the loops.
Code.gs
function testJson() {
try {
let json = {"series":
[{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"Glue","episode_number":"1","media_url":"https://someurl.net/path"},
{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"New Rules","episode_number":"2","media_url":"https://someurl.net/path"}]};
let result = {};
let series = json.series[0];
let name = series.series_name;
result.series = { name: name, seasons: [ { name: series.season_name, season_number: series.season_number, episodes: [] }] };
result.series.seasons[0].episodes.push( { name: series.episode_name, episode_number: series.episode_number, media_url: series.media_url } );
for( let i=1; i<json.series.length; i++ ) {
series = json.series[i];
result.series.seasons.forEach( season => {
if( season.name === series.season_name ) {
season.episodes.push( { name: series.episode_name, episode_number: series.episode_number, media_url: series.media_url } );
}
else {
// add a new season
let j = season.push( { name: series.season_name, season_number: series.season_number, episodes: [] } );
season[j-1].episodes.push( { name: series.episode_name, episode_number: series.episode_number, media_url: series.media_url } );
}
}
);
}
console.log(JSON.stringify(result));
}
catch(err) {
console.log(err);
}
}
Execution log
7:48:56 AM Notice Execution started
7:48:59 AM Info {"series":{"name":"Dance Academy","seasons":[{"name":"season 3","season_number":"3","episodes":[{"name":"Glue","episode_number":"1","media_url":"https://someurl.net/path"},{"name":"New Rules","episode_number":"2","media_url":"https://someurl.net/path"}]}]}}
7:48:57 AM Notice Execution completed

Related

Could someone please explain how to properly write this Javascript function?

I'm looking for someone to show me where I went wrong. The instructions are as follows:
Write the following function (use the songs array to determine what to return).
getSongsNamesByArtist - this function expects a string as an argument
and returns an array containing the names of only those songs in
the songs array whose artist properties are equal to the string
that is passed to it.
So I did this:
let songs = [];
function createSong(name, artist) {
let song = {
name: name,
artist: artist
}
songs.push(song);
return song;
}
var heroes = new createSong("Heroes", "Bowie");
var jubileeStreet = new createSong("Jubilee Street", "Nick Cave");
var buena = new createSong("Buena", "Morphine");
var changes = new createSong("Changes", "Bowie");
var belaLugosi = new createSong("Bela Lugosi is Dead", "Bauhaus");
// I could get only this far:
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
return names;
}
}
}
console.log(getSongsNamesByArtist("Bowie")) // returns: [ 'Heroes' ], but not both of them.
Could you please give me a hint where I went wrong?
Thanks for your time!
The problem is that you are doing an early return in the if statement. So as soon as you are finding a match you return the result.
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
return names; // <- here is your problem
}
}
}
Instead, you want to return after the loop.
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
}
}
return names; // <- here is where you should return
}
You can also consider refactoring this function with the filter and map function in JS
function getSongsNamesByArtist(artist) {
return songs.filter((song) => {
// Filter out the artist you are looking for
return song.artist === artist;
}).map((song) => {
// Reformat your output to only contain the name of the song
return song.name;
});
}
You were returning as soon as first match is found. You have to do it outside for loop . Update your method as below
let songs = [];
function createSong(name, artist) {
let song = {
name: name,
artist: artist
}
songs.push(song);
return song;
}
var heroes = new createSong("Heroes", "Bowie");
var jubileeStreet = new createSong("Jubilee Street", "Nick Cave");
var buena = new createSong("Buena", "Morphine");
var changes = new createSong("Changes", "Bowie");
var belaLugosi = new createSong("Bela Lugosi is Dead", "Bauhaus");
// I could get only this far:
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
}
}
return names;
}
console.log(getSongsNamesByArtist("Bowie"))

Promises in Node js: how to improve?

I'm working on a coding assignment for node.js and I finished it. However, I am wondering if there is any way to improve upon it. The assignment is to take in 3 promises with JSON objects and merge the data as such.
My code does take in the three promises, resolves them, and merges them according to the specifications. I am worried that the code may be too convoluted.
Are there any recommendations to improve it?
Thanks!
{
travelers: [
id,
name,
flights: [
{
legs: [
{
airlineCode,
airlineName,
flightNumber,
frequentFlyerNumber
}
]
}
]
]
}
As I said, my code works but I'm wondering if it can be improved. Here is my code.
'use strict';
// TODO Import what you need
var tripService = require('./api/trip.service.js');
var profile = require('./api/profiles.service.js');
var airlines = require('./api/airlines.service.js');
function getTravelersFlightInfo() {
var tripServiceGet= () => tripService.get();
var profileGet = () =>profile.get();
var airlinesGet = () => airlines.get();
var trips = tripServiceGet().then(function(trip){
return trip;
});
var profiles = profileGet().then(function(profile){
return profile;
});
var airline = airlinesGet().then(function(airlines){
return airlines;
});
function assignLegsToTraveler(passengerFlight, legs , airline , ff){
passengerFlight = {};
passengerFlight.legs = [];
for(let i = 0; i < legs.length; i++){
var airCode = legs[i].airlineCode;
passengerFlight.legs[i] = {};
passengerFlight.legs[i].airlineCode = airCode;
passengerFlight.legs[i].airlineName = airline.airlines.find( x => x.code === airCode).name;
passengerFlight.legs[i].flightNumber = legs[i].flightNumber;
if (ff.hasOwnProperty(airCode) === true){
passengerFlight.legs[i].frequentFlyerNumber = ff[airCode];
}
}
return passengerFlight;
}
function assignFlights(passenger, trips, airline, ff){
for(let i = 0; i < trips.flights.length; i++){
if(trips.flights[i].travelerIds.includes(passenger.id)){
passenger.flights[passenger.flights.length] = assignLegsToTraveler(passenger.flights[passenger.flights.length], trips.flights[i].legs, airline, ff);
}
}
return passenger;
}
return Promise.all([trips, profiles, airline]).then(function([trips, profiles, airline]) {
var result = {};
result.travelers = [];
for(let i = 0; i < profiles.profiles.length; i++){
result.travelers[i] = {};
result.travelers[i].id = profiles.profiles[i].personId;
result.travelers[i].name = profiles.profiles[i].name;
result.travelers[i].flights = [];
assignFlights(result.travelers[i], trips.trip, airline, profiles.profiles[i].rewardPrograms.air);
}
console.log(JSON.stringify(result, null,2));
return result;
});
}
getTravelersFlightInfo();
module.exports = getTravelersFlightInfo;

JavaScript array has elements but length is zero

I've done some searching around the web and nothing seems to solve my problem. I have the following jQuery code:
function youtube_data_parser(data) {
//---> parse video data - start
var qsToJson = function(qs) {
var res = {};
var pars = qs.split('&');
var kv, k, v;
for (i in pars) {
kv = pars[i].split('=');
k = kv[0];
v = kv[1];
res[k] = decodeURIComponent(v);
}
return res;
}
//---> parse video data - end
var get_video_info = qsToJson(data);
if (get_video_info.status == 'fail') {
return {
status: "error",
code: "invalid_url",
msg: "check your url or video id"
};
} else {
// remapping urls into an array of objects
//--->parse > url_encoded_fmt_stream_map > start
//will get the video urls
var tmp = get_video_info["url_encoded_fmt_stream_map"];
if (tmp) {
tmp = tmp.split(',');
for (i in tmp) {
tmp[i] = qsToJson(tmp[i]);
}
get_video_info["url_encoded_fmt_stream_map"] = tmp;
}
//--->parse > url_encoded_fmt_stream_map > end
//--->parse > player_response > start
var tmp1 = get_video_info["player_response"];
if (tmp1) {
get_video_info["player_response"] = JSON.parse(tmp1);
}
//--->parse > player_response > end
//--->parse > keywords > start
var keywords = get_video_info["keywords"];
if (keywords) {
key_words = keywords.replace(/\+/g, ' ').split(',');
for (i in key_words) {
keywords[i] = qsToJson(key_words[i]);
}
get_video_info["keywords"] = {
all: keywords.replace(/\+/g, ' '),
arr: key_words
};
}
//--->parse > keywords > end
//return data
return {
status: 'success',
raw_data: qsToJson(data),
video_info: get_video_info
};
}
}
function getVideoInfo() {
var get_video_url = $('#ytdlUrl').val();
var get_video_id = getUrlVars(get_video_url)['v'];
var video_arr_final = [];
var ajax_url = "video_info.php?id=" + get_video_id;
$.get(ajax_url, function(d1) {
var data = youtube_data_parser(d1);
var video_data = data.video_info;
var player_info = data.video_info.player_response;
var video_title = player_info.videoDetails.title.replace(/\+/g, ' ');
var fmt_list = video_data.fmt_list.split(',');
var video_thumbnail_url = video_data.thumbnail_url;
var video_arr = video_data.url_encoded_fmt_stream_map;
//create video file array
$.each(video_arr, function(i1, v1) {
var valueToPush = {};
valueToPush.video_url = v1.url;
valueToPush.video_thumbnail_url = video_thumbnail_url;
valueToPush.video_title = video_title;
$.each(fmt_list, function(i2, v2) {
var fmt = v2.split('/');
var fmt_id = fmt[0];
var fmt_quality = fmt[1];
if (fmt_id == v1.itag) {
valueToPush.fmt_id = fmt_id;
valueToPush.fmt_quality = fmt_quality;
}
});
video_arr_final.push(valueToPush);
});
});
return video_arr_final;
}
function getUrlVars(url) {
var vars = {};
var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
vars[key] = value;
});
return vars;
}
function fillInOptions(ytOptions) {
//console.log(ytOptions);
//alert(ytOptions[0]);
var ytFill = ytOptions;
console.log(ytFill);
//ytFill.forEach(function(i,v) {
var ytdlOptions = $('#ytdlOptions');
ytFill.forEach(function(i,v) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
return true;
}
function showYTDLLoader() {
$('#ytdlInput').fadeOut(1000, function() {
$('#ytdlLoader').fadeIn(500);
});
var options = getVideoInfo();
//console.log(options);
if (fillInOptions(options) == true) {
//do rest
}
}
function showYTDLOptions() {
return true;
}
function startDownload() {
showYTDLLoader();
}
function hideYTDLLoader() {
$('#ytdlLoader').fadeOut(500);
}
function animateCSS(element, animationName, callback) {
const node = $(element);
node.addClass(animationName);
function handleAnimationEnd() {
node.removeClass(animationName);
node.animationend = null;
if (typeof callback === 'function') callback();
}
node.animationend = handleAnimationEnd();
}
When my button is clicked, I call showYTDLLoader() which gets an array of objects from the YouTube API that looks like this:
[
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=22&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&ratebypass=yes&dur=917.768&lmt=1572418007364260&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5535432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRgIhAIp-4gyUTLoXFetbY0ha_YnR7DJqsp_MNjjIxqDdfPZJAiEA_WPd21jgX9broBcigf8rcSEVoJb2_NX7t3XZQqytsSM%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "22",
"fmt_quality": "1280x720"
},
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=18&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&gir=yes&clen=44248820&ratebypass=yes&dur=917.768&lmt=1572416976690256&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5531432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cgir%2Cclen%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRQIhANTZJlBHFWQWCnfK11yvLiPUV26c6NzvqIMKjDwmsByMAiBUSy0ZJMo4GdHSiRU4xBDDLxLtzwKZAqAKCiB-1aViDQ%3D%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "18",
"fmt_quality": "640x360"
}
]
But when I try and loop through each entry with fillInOptions(), my loop is never completed because the length is apparently zero. However, when I dump the array using console.log() it tells me the length is 2, and displays the above. I need to be able to add each option to my dropdown.
Thankyou!
UPDATE: Added full code, sorry!
It looks like your .forEach() is the root of the problem. The parameters of a forEach are currentValue, index like this: array.forEach(function(currentValue, index) {}); but it looks like you're using them in the opposite way
Try rewriting that iteration to this:
ytFill.forEach(function(v, i) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
Notice the difference in the order of v and i in the parameters.

can't store data properly to implement the Breadth-first search in application like the oracle of bacon (object communication)

I have .JSON file with objects that represent movies shown below. I'am trying to store the data in that file in a structure so i can use it in implementing the breadth-first search to build an application like (the oracle of bacon). I have Node objects and graph object to store all the nodes. I need to make a node for every movie and every actor. my problem is that the hasNode(node) -i made to only add the actor if i doesn't exist in the nodes of the graph- always returns false.
#sample JSON object:
{
"title": "Diner",
"cast": [
"Steve Guttenberg",
"Daniel Stern",
"Mickey Rourke",
"Kevin Bacon",
"Tim Daly",
"Ellen Barkin",
"Paul Reiser",
"Kathryn Dowling",
"Michael Tucker",
"Jessica James",
"Colette Blonigan",
"Kelle Kipp",
"Clement Fowler",
"Claudia Cron"
]}
function Graph() {
this.nodes = [];
this.graph = {};
}
Graph.prototype.addNode = function (node) {
this.nodes.push(node);
}
Graph.prototype.hasNode = function (node) {
for (var i = 0; i < this.nodes.length; i++) {
if (this.nodes[i].name == node.name) {
return true;
} else {
return false;
}
}
}
function Node(name) {
this.name = name;
this.edges = [];
this.searched = false;
this.parent = null;
}
#My setup function:
var data;
var graph;
function preload() {
data = loadJSON('kevinbacon.json');
}
function setup() {
noCanvas();
graph = new Graph();
var movies = data.movies;
for (var i = 0; i < movies.length; i++) {
var movie = new Node(movies[i].title);
graph.addNode(movie);
var cast = movies[i].cast;
for (var j = 0; j < cast.length; j++) {
var actor = new Node(cast[j]);
if (!(graph.hasNode(actor))){
graph.addNode(actor);
}
}
}
console.log(graph);
}
i excpect the output to be the graph object with all the actors (not duplicated) and movies but i get it with actors duplicated.
the problem is that youre immediately returning even if the name doesnt equal in the first checked element .
Instead you should only abort if the name is found otherwise it wont check the rest of the names
//sample JSON object:
var example=JSON.parse('{ "title": "Diner", "cast": [ "Steve Guttenberg", "Daniel Stern", "Mickey Rourke", "Kevin Bacon", "Tim Daly", "Ellen Barkin", "Paul Reiser", "Kathryn Dowling", "Michael Tucker", "Jessica James", "Colette Blonigan", "Kelle Kipp", "Clement Fowler", "Claudia Cron" ]}');
function Graph() {
this.nodes = [];
this.graph = {};
}
Graph.prototype.addNode = function (node) {
this.nodes.push(node);
}
Graph.prototype.hasNode = function (node) {
for (var i = 0; i < this.nodes.length; i++) {
if (this.nodes[i].name == node.name) {
return true;
}
}
return false
}
function Node(name) {
this.name = name;
this.edges = [];
this.searched = false;
this.parent = null;
}
//My setup function:
var data;
var graph;
(function setup() {
graph = new Graph();
var movies = [example ];
for (var i = 0; i < movies.length; i++) {
var movie = new Node(movies[i].title);
graph.addNode(movie);
var cast = movies[i].cast;
for (var j = 0; j < cast.length; j++) {
var actor = new Node(cast[j]);
if (!(graph.hasNode(actor))){
console.log("adding node",actor)
graph.addNode(actor);
}
}
}
console.log(graph);
})();

Change object data

I have this text file (800kb url) inwhich a some JSON data is stored. After I load the data from the text file I would like to change stuff and loop over it.
I did this using this sample simple function;
var convertPriceFormat = function(content){
var obj = {};
for(var appid in content){
var gameEntry = content[appid];
for(var hashName in gameEntry){
var entry = gameEntry[hashName];
obj[hashName] = entry.price;
};
console.log(Object.keys(gameEntry).length);
};
return obj;
}
There's four sub-objects in the returned object ofwhich they all have about 3000 entries, that's not like a huge amount.
All data per entry is structuated like so;
'Pinstripe Suit Jacket': {
average_price: 0.02,
listings: 11,
volume: 1185.03,
price: 0.03
}
Problem is; for some odd reason when I log the length of the gameEntry (so the total of entries per sub-object), there's like 12 seconds between the first log and the second log.
Why is this?
Load time (relative since start, numbers are the amount of entries it had to loop over):
2373 '3.48s'
5769 '24.422s'
1405 '25.326s'
641 '25.436s'
Most likely the entry does not really look like what you think it does. Try this code or a variant of it to trace what is going on.
var convertPriceFormat = function(content) {
var obj = {};
for (var appid in content) {
console.log(`appid: ${appid}`)
var gameEntry = content[appid];
for (var hashName in gameEntry) {
console.log(`hashName: ${hashName}`)
var entry = gameEntry[hashName];
obj[hashName] = entry.price;
};
console.log(Object.keys(gameEntry).length);
};
return obj;
}
const entry1 = {
'Pinstripe Suit Jacket': {
average_price: 0.02,
listings: 11,
volume: 1185.03,
price: 0.03
}
}
const entries = []
for (let i = 0; i < 3000; i++) {
entries.push(entry1)
}
console.log(`Number of entries: ${entries.length}`)
convertPriceFormat(entries.slice(0,3))
use hasOwnProperty to filter for in loop.
var convertPriceFormat = function (content) {
var obj = {};
for (var appid in content) {
var gameEntry = content[appid];
for (var hashName in gameEntry) {
var entry = gameEntry[hashName];
obj[hashName] = entry.price;
};
};
return obj;
}
var convertPriceFormat2 = function (content) {
var obj = {};
for (var appid in content) {
if (content.hasOwnProperty(appid)) {
var gameEntry = content[appid];
for (var hashName in gameEntry) {
if (gameEntry.hasOwnProperty(hashName)) {
var entry = gameEntry[hashName];
obj[hashName] = entry.price;
}
}
}
}
return obj;
}
const entry1 = {
'Pinstripe Suit Jacket': {
average_price: 0.02,
listings: 11,
volume: 1185.03,
price: 0.03
}
}
const entries = []
for (let i = 0; i < 3000; i++) {
entries.push(entry1)
}
console.log(`Number of entries: ${entries.length}`)
console.time("time")
convertPriceFormat(entries)
console.timeEnd("time")
console.time("time2")
convertPriceFormat2(entries)
console.timeEnd("time2")
results are better in avarage

Categories

Resources