Syncano Codebox - Call API - parse JSON - get Reference - Save new Objects - javascript

I am using Syncano as a baas, where I am trying to call an external API to receive a JSON array. This JSON needs to be parsed and afterwards stored in syncano. Before that I need to receive the reference object from the DB to link it to the new team object.
I receive the team (json) array & reference object successfully. But I am unable to get the new data stored, as only 12-14 teams (has to be 18) get saved.
I tried this & that with promises but it didnĀ“t work out. Anyone a good advise how to rewrite the code to store all data? Thank you - here is what I have so far...
//TODO: get from ARGS when executing this codebox
var teamKey = 394;
var requestURL = 'http://api.football-data.org/v1/soccerseasons/' + teamKey + "/teams";
var request = require("request");
var Syncano = require('syncano');
var Promise = require('bluebird');
var account = new Syncano({
accountKey: "abc"
});
var promises = [];
//from: http://docs.syncano.io/v1.0/docs/data-objects-filtering
//"_eq" means equals to
var filter = {
"query": {
"apikey": {
"_eq": apiKey
}
}
};
request({
headers: {
'X-Auth-Token': 'abc'
},
url: requestURL,
'Content-Type': 'application/json;charset=utf-8;',
method: 'GET',
}, function(error, response, body) {
if (error) {
console.log(error);
} else {
var json = JSON.parse(body);
var teamArray = json.teams;
var newObject;
account.instance('instance').class('competition').dataobject().list(filter)
.then(function(compRes) {
var competitionID = compRes.objects[0].id;
for (var i = 0; i < teamArray.length; i++) {
newObject = {
"name": teamArray[i].name,
"nameshort": teamArray[i].code,
"logo": teamArray[i].crestUrl,
"competition": competitionID
};
(account.instance('instance').class('teams').dataobject().add(newObject).then(function(res) {
console.log(res);
}).catch(function(err) {
console.log("Error eq: " + err);
})
);
}
}).catch(function(err) {
console.log(err);
});
}
});

The issue might be you are finishing the request process before all the save calls are made, you could try Promise.all():
account.instance('instance').class('competition').dataobject().list(filter)
.then(function(compRes) {
var competitionID = compRes.objects[0].id, promises=[];
for (var i = 0; i < teamArray.length; i++) {
newObject = {
"name": teamArray[i].name,
"nameshort": teamArray[i].code,
"logo": teamArray[i].crestUrl,
"competition": competitionID
};
promises.push(account.instance('instance').class('teams').dataobject().add(newObject).then(function(res) {
console.log(res);
}).catch(function(err) {
console.log("Error eq: " + err);
})
);
}
return Promise.all(promises);
}).catch(function(err) {
console.log(err);
});
if too many parallel calls at a time is the issue then chain one call after other:
account.instance('instance').class('competition').dataobject().list(filter)
.then(function(compRes) {
var competitionID = compRes.objects[0].id, promise = Promise.resolve();
function chainToPromise(promise, teamObj, waitTime){
waitTime = waitTime || 500;
return promise.then(function(){
return new Promise(function(resolve, reject){
setTimeout(resolve, waitTime);
});
}).then(function(){
return account.instance('instance').class('teams').dataobject().add(teamObj);
}).then(function(res) {
console.log(res);
}).catch(function(err) {
console.log("Error eq: " + err);
});
}
for (var i = 0; i < teamArray.length; i++) {
newObject = {
"name": teamArray[i].name,
"nameshort": teamArray[i].code,
"logo": teamArray[i].crestUrl,
"competition": competitionID
};
promise = chainToPromise(promise, newObject);
}
return promise;
}).catch(function(err) {
console.log(err);
});

Related

Iterating through list and make sequential network calls

How do i iterate through a list and make sequential network calls using a sdk?
I am trying to use Coinbase's Node sdk and get the first 10 transactions for all accounts.
I have a list of accounts, and i iterating through them and calling client.account, client.transactions, and client.transactions(pagination). And im adding the results to an array of transactions and returning that array.
I couldn't get this to work with async/await or request-promises.
Any ideas?
https://developers.coinbase.com/api/v2#transactions
var rp = require('request-promise');
var coinbase = require('coinbase');
var client = new coinbase.Client({ 'apiKey': 'keyStuff', 'apiSecret': 'secretStuff' });
var accountList = ['acct1','acct2','acct3',];
var transactionList = [];
try {
let ps = [];
accountList.forEach(acctId => {
var account = client.getAccount(accountId, null);
ps.push(rp(account));
});
Promise.all(ps)
.then(responses => {
for (var i = 0; i < responses.length; i++) {
var result = responses[i];
rp(result.account.getTransactions(null))
.then(res => {
res.pagination = 10;
return rp(result.account.getTransactions(null, res.pagination));
}).catch(err => console.log(err))
.then(txns => {
try {
if (txns.length > 0) {
txns.forEach(function(txn) {
var transaction = {
"trade_type": "",
"price": ""
};
transaction.trade_type = txn.type;
transaction.price = txn.native_amount.amount;
transactionList.push(transaction);
});
}
}
catch (err) {
console.log(err);
}
});
}
}).catch(err => console.log(err));
return transactionList;
//-------------------------------------------------------------------
// if (accountList.length > 0) {
// for (let acctId of accountList) {
// console.log("account id: " + acctId);
// await delayTransactions(acctId);
// }
// console.log("got here last");
// return transactionList;
// }
}
catch (error) {
console.log(error);
}
The commented-out delay method has nested async calls like this:
await client.getAccount(accountId, async function(err, account) {
if (err) {
console.log(err);
}
else {
await account.getTransactions(null, async function(err, txns, pagination) {
.
.
.
Solved it by using async/await and promises. awaiting the coinbase methods wouldn't work because they aren't async functions (surprise!).
function delayedMethod() {
new Promise(resolve => {
client.getAccount(accountId, async function(err, account) {
if (err) {
console.log(err);
}
else {
account.getTransactions(null, async function(err, txns, pagination) {
.
.
.
resolve();
});
}

why my array is empty?

i can not figure out why my array is empty while the console is showing output:
I'm fetching data from dynamodb and trying to make a modified response json array i can print the values of dynamodb response but when i push it into array the returned array is empty here is my code.
Here is Util.js file
const dynamo = require('./dynamo.js')
var myjson = [];
exports.myjson = [];
exports.maketimetabledata = function(callback) {
var table = "timetable";
for (i = 1; i <= 2; i++) {
dynamo.docClient.get({
TableName: table,
Key: {
"id": i
}
}, function(err, data) {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
return err;
} else {
dynamores = JSON.parse(JSON.stringify(data));
myjson.push(i);
}
});
console.log(myjson);
}
callback("done");
};
and here is my partial index file:
app.get('/', (req, res) => {
var myjson = [];
util.maketimetabledata(function(returnvalue) {
if (returnvalue) {
console.log(util.myjson);
}
});
});
output :
[] [] []
undefined
{ response from dynamo db for debugging purpose}
Assuming dynamo.docClient.get() returns a Promise, You can use Promise.all() to wait for all the promise to complete then invoke the callback method.
//Use Promise.all()
exports.maketimetabledata = function (callback) {
var table = "timetable";
for (i = 1; i <= 2; i++) {
var table = "timetable";
var promiseArray = [];
for (i = 1; i <= 2; i++) {
var promise = dynamo.docClient.get({
//Your code
});
promiseArray.push(promise)
}
console.log(myjson);
}
Promise.all(promiseArray).then(function () {
callback(myjson);
});
};
//Usage
util.maketimetabledata(function (myjson) {
if (returnvalue) {
console.log(myjson);
}
});
If the method is not returning Promise
var promise = new Promise(function (resolve, reject) {
dynamo.docClient.get({
TableName: table,
Key: {
"id": i
}
}, function (err, data) {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
reject();
return err;
} else {
dynamores = JSON.parse(JSON.stringify(data));
myjson.push(i);
resolve();
}
});
});

Javascript Execute at end of Async Loop

I'm awful with Async code in Javascript and have been stuck on something for a while now.
I'm working with WebSql and just going through database initialization steps but one of the loops is not executing in the way I expect it to.
$(document).ready(function() {
initdatabase();
});
function initdatabase() {
var db = window.openDatabase("nothing", "1.0", "nothing", 2 * 1024 * 1024);
db.transaction(function(trans) {
trans.executeSql("CREATE TABLE", [], function(trans, result) {
// success
defaultdata(db);
}, function(error) {
// failed
});
});
}
function defaultdata(db) {
db.transaction(function(trans) {
var lo_data = [
{code:"CODE01", desc:"Code 01 Desc"},
{code:"CODE02", desc:"Code 02 Desc"},
{code:"CODE03", desc:"Code 03 Desc"}
];
for(i = 0; i < lo_data.length; i++) {
trans.executeSql("INSERT", [lo_data[i].code, lo_data[i].desc], function(trans, result) {
// success
console.log("INS : " + i);
}, function(error) {
// failed
});
}
console.log("END");
});
}
But the log to indicate the end is executing before the for loop has finished. If I try validate that the data has been inserted I always get fails because the loop hasn't completed the inserts.
Google says that async code should be handled with promises but I can't find examples of promises being used in an instance like this.
Any help would be greatly appreciated
Convert each callback into a promise, and then use Promise.all
const loDataPromises = lo_data.map(({ code, desc }) => {
return new Promise((resolve, reject) => {
trans.executeSql(
"INSERT",
[code, desc],
function(trans, result) {
console.log('success');
resolve();
},
function(error) {
console.log('failed');
reject();
}
);
});
});
Promise.all(loDataPromises)
.then(() => {
console.log('all done');
});
I haven't been able to find any clear code examples on the internet so I wanted to post the working version here as the answer. Hopefully it can benefit someone also trying to understand promises and promise loops.
After a complete overhaul I've managed to get it working in a way that makes sense. I've change it to be executed as a promise chain and then the function with the for loop is utilizing the promise all logic.
$(document).ready(function() {
////
// promise chain
////
console.log("BEGIN");
f_initdatabase().then(function(result) {
return f_defaultdata(result.db);
}).then(function(result) {
console.log("END");
}).catch(function(result) {
// abandon all hope
});
});
////
// single promise usage
////
function f_initdatabase() {
return new Promise(function(resolve, reject) {
console.log(" INIT DB");
var lo_result = {db:null};
var lv_db = window.openDatabase("thenothing", "1.0", "The Nothing DB", 2 * 1024 * 1024);
lv_db.transaction(function(trans) {
trans.executeSql ("create table if not exists dummydata (dd_idno integer primary key, dd_code text not null, dd_desc text not null)", [], function(trans, results) {
console.log(" INIT DB : DONE");
lo_result.db = lv_db;
resolve(lo_result);
}, function(error) {
lo_result.db = null;
reject(lo_result);
});
});
});
}
////
// loop promise all usage
////
function f_defaultdata(lv_db) {
return new Promise(function(resolve, reject) {
console.log(" DEF DATA");
var lo_result = {db:null};
lv_db.transaction(function(trans) {
var la_promises = [];
var lo_data = [
{dd_code:"CODE01", dd_desc:"Code 01 Desc"},
{dd_code:"CODE02", dd_desc:"Code 02 Desc"},
{dd_code:"CODE03", dd_desc:"Code 03 Desc"}
];
for(i = 0; i < lo_data.length; i++) {
console.log(" INS : " + i);
trans.executeSql (" insert into dummydata (dd_code, dd_desc) values (?, ?)", [lo_data[i].dd_code, lo_data[i].dd_desc], function(trans, results) {
la_promises.push(resolve(lo_result));
}, function(error) {
la_promises.push(reject(lo_result));
});
}
Promise.all(la_promises).then(function(results) {
console.log(" DEF DATA : DONE");
lo_result.db = lv_db;
resolve(lo_result);
}).catch(function() {
lo_result.db = null;
reject(lo_result);
});
});
});
}
This gives the output according to the flow needed
BEGIN
INIT DB
INIT DB : DONE
DEF DATA
INS : 0
INS : 1
INS : 2
DEF DATA : DONE
END

mongoose-random response 500

I've just opened a nodeJS code trying to get random documents from my mongoose collection using mongoose-random, but for any reason when I call to findRandom() method, it responses a 500.
test.js
Here bellow I paste my code:
var mongoose = require('mongoose');
var random = require('mongoose-random');
var Promise = require('bluebird');
mongoose.Promise = Promise;
var TestSchema = new mongoose.Schema({
_id: {
type: Number,
default: 0
}
});
TestSchema.plugin(random, {path: 'r'});
TestSchema.statics = {
start: function (value) {
var array = [], i = 1;
for (i; i < value; i += 1) {
array.push({ _id: i });
}
return this.create(array);
},
getRandom: function () {
return new Promise(function(resolve, reject) {
TestSchema.findRandom().limit(10).exec(function (err, songs) {
if (err) {
reject(err);
} else {
resolve(songs);
}
});
});
}
};
module.exports = mongoose.model('TestSchema', TestSchema);
routes.js
var router = require('express').Router();
var path = require('path');
var Promise = require('bluebird');
var request = require('request');
var test = require('./models/test.js');
router.get('/fill', function (req, res) {
test.start(40)
.then(function () {
res.status(200).send('You can start your hack :)');
})
.catch(function (error) {
res.status(400).send(error);
});
});
router.get('/vote', function (req, res) {
test.getRandom()
.then(function (data) {
res.status(200).send(data);
})
.catch(function (error) {
res.status(400).send(error);
});
});
module.exports = router;
Reading other post here as a solution purposes to use syncRandom() method, but that doesn't work for me. Neither using random()
Any help? Thanks in advice.
UPDATE
Digging more into the issue, I've realiced my model TestSchema, which should contain mongoose-random methods is being overrided, so I only have my statics methods.
Don't set statics to a new object, just add methods to it:
TestSchema.statics.start = function (value) {
var array = [], i = 1;
for (i; i < value; i += 1) {
array.push({ _id: i });
}
return this.create(array);
};
TestSchema.statics.getRandom = function () {
return new Promise(function(resolve, reject) {
TestSchema.findRandom().limit(10).exec(function (err, songs) {
if (err) {
reject(err);
} else {
resolve(songs);
}
});
});
};
However, if your MongoDB server is at least 3.2, you're probably better off using the built-in $sample pipeline operator instead of a plugin to select random documents.
test.aggregate([{$sample: 10}], callback);

Nested promise in a for loop not behaving as expected

I am having trouble extending a Promise inside a .then(). I am trying to perform DB updates in a for-loop and then close the database after all records are processed. However the application exits with process.exit() right away which means that process.exit() was executed even before all db updates were finished. I am pretty sure I am doing something wrong with the nested promise.
var myDB;
function doSomething() {
return MongoClient.connect(DB_CONNECTION).then(function(db) {
myDB = db;
var collection = db.collection(COLLETION_NAME);
for (var i = 0; i < 10; i++) {
promise.then(function{
collection.update({
symbol: items[i].symbol
}, {
$set: {
value: 123
}
}, {
upsert: true
});
});
}
})
}
var promise = doSomething();
promise.then(function(){
console.log("DONE");
myDB.close();
process.exit();
});
It looks like you are getting a promise back from the MongoClient.connect method so why not use that to chain together. I've put a quick sample together below based on your code:
function doSomething(db) {
return new Promise(function(resolve, reject){
var collection = db.collection(COLLETION_NAME);
for (var i = 0; i < 10; i++) {
collection.update({
symbol: items[i].symbol
}, {
$set: {
value: 123
}
}, {
upsert: true
});
}
resolve(db);
})
}
function connectToDB() {
return MongoClient.connect(DB_CONNECTION);
}
function closeDB(db) {
return new Promise(function(resolve, reject){
db.close();
resolve();
});
}
connectToDB().then(function(db){
return doSomething(db);
}).then(function(db){
return closeDB(db);
}).then(function(){
console.log("DONE");
process.exit();
}).catch(function(error){
console.log('Something went wrong: ' + error);
});
Updated code as per #RayonDabre 's suggestion
function doSomething() {
return MongoClient.connect(DB_CONNECTION).then(function(db) {
myDB = db;
var collection = db.collection(COLLECTION_NAME);
var promises = [];
for (var i = 0; i < 10; i++) {
var innerPromise = collection.update({
symbol: items[i].symbol
}, {
$set: {
value: 123
}
}, {
upsert: true
});
promises.push(innerPromise);
}
return Promise.all(promises);
});
}
var promise = doSomething();
promise.then(function(){
console.log("DONE");
myDB.close();
process.exit();
});

Categories

Resources