Meteor call in a loop. How to prevent multiple call? - reactjs

The method call "Insert All sms data" run more than once I tried to prevent using counter variable but on client side it run once and on the server side it runs x time as shown in the image, thus adding data to db multiple timres which I do not want, this should add to db only once. I want also add another call whith in method call "Insert All sms data" which should run x as the loop. I stuck here.
Meteor 1.8 react 16.8
imports/api/kuser.js
'Find all numbers' (smsText) {
if(!this.userId) {
throw new Meteor.Error('not-authorized');
}
let counter = 0;
return userKisandb.find({
userId: this.userId
}).fetch().map((Mob) => {
// return Mob.Mnumber
if(Mob.Mnumber) {
Meteor.call('Send to all',Mob.Mnumber,smsText,(err,resp) => {
//sms.js
if(err){
console.log("send all numbers error2", err);
} else {
console.log("send all numbers ", resp);
if(counter === 0) {
Meteor.call('Insert All sms data',smsText,counter,(err,resp1) => {
//get inserted data id
//allSmsdb
if(err){
console.log("Insert All sms data error", err);
} else {
console.log("this should run only once ",counter);
//Another call to be added which should run x times
}
})
counter++
}
}
});
} //Mob.Mnumber
});
},
and the method 1 is
'Send to all'(mob,text) {
return "sucess";
},
method 2 is
'Insert All sms data' (smstext,counter) {
if(!this.userId) {
throw new Meteor.Error('not-authorized');
}
console.log("Inserted same data x times",counter);
if(counter === 0) {
return allSms.insert({
smstext,
userId: this.userId,
updatedAt: moment().valueOf(),
});
}
},
And output is

Meteor methods can be called from the front end, asking the back end to do something. It doesn't make sense for a back end method to do a Meteor.call, because it's already on the back end. It will work, kind of, but then you get into trouble because your counter isn't passed around as you expect.
Make your method only work on the server, and just loop around the data, doing all of the work, rather than breaking it up into pieces like you have.

Related

React APP makes a ton of API Calls and crashes

I am making a simple app that makes an api request to my local server and gets some data and puts it on a chart from trading view. This should be pretty simple as everything is just for practice, but when I change some of the values on my server and make the call, the app keeps making the call like 35 times before the server crashes and then the app just says
"net::ERR_CONNECTION_REFUSED"
and doesn't display the data as it should.
This is the whole code, it has two parts. One parts makes the call to get example data of name and another call to get example data that will go to the chart (the second part is the issue.)
This is the code just for the second part:
getBars: async (
symbolInfo,
resolution,
periodParams,
onHistoryCallback,
onErrorCallback
) => {
try {
if (resolution === '1D') {
resolution = 1440;
}
const response2 = await axios.get('http://localhost:8000/chart');
console.log('got bars data');
const bars = response2.data.map((el) => ({
time: new Date(el.timeInterval.minute).getTime(), // date string in api response
low: el.low,
high: el.high,
open: Number(el.open),
close: Number(el.close),
volume: el.volume,
}));
if (bars.length) {
onHistoryCallback(bars, { noData: false });
} else {
onHistoryCallback(bars, { noData: true });
}
console.log('bars done');
} catch (err) {
console.log({ err });
}
};
So what happens is that the console.log "got bars data" and "bars done" repeats many times until my localhost:8000 server crashes and then the app gives the error I showed above, because of this it doesn't display the data. I have no Idea why this may be happening,
This is what the data looks like for the one that does not works:
{"timeInterval":{"minute":"2022-03-14T23:45:00Z"},"volume":0.05,"high":3.910209183178435e-9,"low":3.910209183178435e-9,"open":"3.910209183178435e-09","close":"3.910209183178435e-09"}
This is for the one that works:
{"timeInterval":{"minute":"2022-03-17T15:00:00Z"},"volume":0.05,"high":0.00001255389794727055,"low":0.00001255389794727055,"open":"1.255389794727055e-05","close":"1.255389794727055e-05"}
I would appreciate any help, thanks!
EDIT
I just noticed, with the data set that works, console.log('got bars data') and console.log('bars done') don't occur for some reason, but the data still shows up on the chart even though the console doesn't log.

How do I execute this async statement with snowflake-sdk and obtain the return value?

How do I store something from a conn.execute complete block?
https://docs.snowflake.com/en/user-guide/nodejs-driver-use.html#executing-statements
Basically I want to do something like this:
async function checkRecords(conn: Connection, sqlText: string): Promise<number> {
return new Promise ((resolve, reject) => {
try {
conn.execute({
sqlText: sqlText,
complete: function(err, stmt, rows) {
if (err) {
reject(err);
} else {
let ret = parseInt(rows[0].COUNT);
return Promise.resolve(ret);
}
}
});
} catch (err) {
error(err);
}
});
}
I think my question is similar to How can I execute Snowflake statement in async mode using NodeJs Snowflake driver? but I did not find any answer there.
Because of the async nature of the complete I never manage to return the value of the complete block.
I've tried to make it await, I've tried to make the function async and return a promise the point is that when I then call the function it still always ignores the wait (and I see in the log the executions with the actual result after my code that was supposed to wait for it already moved one).
Honestly I did not find any good example of this based in Snowflake SDK so I was wondering if anyone knows of a good example to test thigs.
I've seen a lot of different posts on javascript about this like
How to return the response from an asynchronous call
But honestly I do not get it so I really wanted to know if someone has some example based on the Snowflake SDK I could use for inspiration.
I will close this question but somehow I can't make my code wait on the promise
Basically this code just does nothing.
checkRecords(conn, stmtTextStage).then(value => {
if (value > 0) {
log(`STAGE.${name} contains ${value} unique records!`);
} else {
log(`STAGE.${name} contains no records!`, 'WARN');
}
});
well I did manage to make it work but took me a while because I really don't understand this Promise resolve thing but something like this did work:
async function checkRecords(conn: Connection, sqlText: string): Promise<number> {
return new Promise ((resolve, reject) => {
try {
conn.execute({
sqlText: sqlText,
complete: function(err:SnowflakeError, stmt: Statement, rows: any[]) {
if (err) {
error(`${stmt.getSqlText()} : ${err.code}`);
reject(0);
} else {
if (rows.length === 1) {
resolve(parseInt(rows[0].COUNT));
} else {
error(`${sqlText} returned un-expeted rows!`);
reject(0);
}
}
}
});
} catch (err) {
error(err);
}
});
}

Can Looping Through a Function "Too Fast" Break It (Node.js)

I am trying to accumulate API responses on a server and return them to the client as a single object. To do this I am looping through items in an array and mapping the responses back into the original object. This is working fine for an array of length 1, but logs blanks when looping through larger arrays.
When looping through the array does Node create a new instance of the function or does it keep passing data into the same function even if it hasn't returned a value yet?
loopThroughArray(req, res) {
for(let i=0; i<req.map.length; i++) {
stack[i] = (callback) => {
let data = getApi(req, res, req.map[i], callback)
}
}
async.parallel(stack, (result) => {
res.json(result)
})
}
....
function getApi(req, res, num, cb) {
request({
url: 'https://example.com/api/' + num
},
(error, response, body) => {
if(error) {
// Log error
} else {
let i = {
name: JSON.parse(body)['name'],
age: '100'
}
console.log(body) // Returns empty value array.length > 1 (req.map[i])
cb(i)
}
})
If Node is overloading the function, how can I ensure data has been received before running the function again?
The api calls are async.
When running the loop, the code is making many rest calls without waiting for the answer.
If the loop is not too big then you could synchronize the calls using recursion.
You could also synchronize the calls using nimble:
http://caolan.github.io/nimble/
a loop waits for the method inside it to finish before it loop back. so there's really no such thing as a loop that moves really fast unless you're using "threading" which your obviously not.

How do you push function calls onto an array without calling them in Node JS for using Q?

I'm looking to create an array of functions to call dynamically, which will be later used in the Q.all([]) promise call.
For example;
//data is previously generated
var promiseArray = [];
for (var i = 0; i < data.length; i++){
promiseArray.push(functionCall(data[i]))
}
Q.all(promiseArray).then(function(){
//Do something
})
How would I push to the array without calling the function until the Q.all statement? I don't want to call it in the for loop as it will not catch any errors and I can't process the response further.
EDIT:
So to clarify my problem (as I don't think I was as clear as I should have been), here is a solution for a static data length of say 3;
//data is previously generated
var data = [12432432,4324322392,433324323];
//Each function call can happen in parallel or series as its an external POST to an API
//I'm not bothered about speed for this application (as its low throughput) and can wait a few seconds for each
// response
//FunctionCall returns a promise
functionCall(data[0]).then(function(){
//Log success / failure to mongo
});
functionCall(data[1]).then(function(){
//Log success / failure to mongo
});
functionCall(data[2]).then(function(){
//Log success / failure to mongo
});
//OR
functionCall(data[0]).then(function(){
//Log success/failure to mongo
functionCall(data[1]).then(function(){
//Log success/failure to mongo
functionCall(data[2]).then(function(){
//Log success/failure to mongo
});
});
});
But I wont know the length of data until runtime
If I understand correctly, you want to call functionCall for an array of items, and have Q.all resolve once all the promises returned by functionCall have completed regardless if they resolve or reject - if you don't care about the results (as you don't seem to in your code) simply handle the rejection in the promise you push - i.e.
var promiseArray = [];
for (var i = 0; i < data.length; i++) {
promiseArray.push(functionCall(data[i]).then(function(result) {
// log success
return logToMongoFunction(result);
}, function(error) {
// log failure
return logToMongoFunction(error);
}).catch(function(error) {
// catch and ignore any error thrown in either logToMongoFunction above
return;
}));
}
Q.all(promiseArray).then(function () {
//Do something
});
Note: the above can be simplified to
Q.all(data.map(function (item) {
return functionCall(item).then(function(result) {
// log success
return logToMongoFunction(result);
}, function(error) {
// log failure
return logToMongoFunction(error);
}).catch(function(error) {
// catch and ignore any error thrown in either logToMongoFunction above
return;
});
})).then(function() {
//Do something
});
the edited question suggests you can perform the actions in series also - in series it would be
data.reduce(function(promise, item) {
return promise.then(function() {
return functionCall(item).then(function(result) {
// log success
return logToMongoFunction(result);
}, function(error) {
// log failure
return logToMongoFunction(error);
}).catch(function(error) {
// catch and ignore any error thrown in either logToMongoFunction above
return;
});
});
}, Promise.resolve()).then(function() {
// all done
});
instead of Promise.resolve() you could use whatever Q has as an equivalent that creates a resolved promise
logToMongoFunction would log to mongo and needs to return a promise if you need to wait for that to finish before processing the next data item. If you do not need to wait for the mongo logging to complete then there's no need for that function to return a promise
i will recommend using Promise.mapSeries or async library for this because its very easy to catch errors. One more thing looping using a for loop doesnt seems to be good approach if you have database calls in the callback because that might flush the calls to the database and node.js can have memory issues or node.js wont be able to entertain any other request because it will be busy entertaining the request in the for loop. so its always good to run loop serially or limit the numer of parallel executions at a time.
please see example below
This will run Array serially one at a time when 1st one completes execution next will be called
async.eachOfSeries(data, function(dataInstance, key, next) {
functionCall(dataInstance).then(function(){
next();
}).catch(funtion(err){
next(err);
})
}, function() {
//iteration completed
});
OR
async.eachOfSeries(data, function(dataInstance, key, next) {
functionCall(dataInstance, function(err , result){
if(err)
{
console.log(err);
next(err);
}
else
next();
});
}, function() {
//iteration completed
});

Angular service and pouchdb

How do you use angularjs service to call pouchdb and return the data to the controller? I have been working on a ionic app with pouchdb for local storage. I have a simple crud app built in a controller. Now I want to start to move the pouchdb calls into a service. I haven’t been able to get back data from the service. How would I use a service to call pouchdb to get all docs and return it to the controller?
One strategy that I think could work very well for Angular services is this one. It describes a method for keeping an in-memory array synced with the result of PouchDB's allDocs().
Since it's an array that automatically stays synced with PouchDB, you can just do an ng-repeat on it, and you're done. :)
Although your question is a year old, it deserves an answer.
You might want more than one service i.e. one to use in the controller and another for the backend database storage. For example, in the controller:
(function () {
'use strict';
angular
.module('app.services')
.factory('db',db);
db.$inject = ['$db'];
function db($db) {
var data = {}; // set up a data object to receive document(s)
return {
getDoc: getDoc,
getList: getList,
save: save,
saveBatch: saveBatch
};
// get a single document using the id
function getDoc(id) {
$db.getDoc(id)
.then(
function onSuccess(doc) {
// success so update the view model
angular.extend(data,doc); // use angular.extend to shallow copy object so that it can be returned in full
},
function onError() {
// failure to get document
}
);
return data;
}
// retrieve a group of documents where key is the prefix of the data you want
function getList(key) {
$db.getList(key).then(
function onSuccess(docs) {
// success so update the view model details
angular.forEach(docs.rows, function (value) {
this.push(value.doc);
}, data);
// now you can sort data or anything else you want to do with it
},
function onError() {
// no data found
}
);
return data;
}
// save a single viewItem
function save(viewItem) {
$db.update(viewItem).then(
function onSuccess() {
// success so update view model if required
},
function onError(e) {
console.log(e); // unable to save
}
);
}
// save an array of viewItems
function saveBatch(viewItems) {
$db.updateBatch(viewItems).then(
function onSuccess() {
// success so update the view model if required
},
function onError(e) {
console.log(e); // unable to save
}
);
}
}
})();
For the backend, something like this:
(function () {
'use strict';
angular
.module('app.services')
.factory('$db',$db);
$db.$inject = ['$q'];
function $db($q) {
var db;
return {
setLocalDB: setLocalDB,
update: update,
updateBatch: updateBatch,
getDoc: getDoc,
getAllDocs: getAllDocs,
getList: getList
};
// ------ DATABASE OPENING HANDLER(S) ------
// set to any named database
function setLocalDB(dbName) {
db = new PouchDB(dbName);
return db.info()
.catch(failedCheck()); // returns a promise to either work or fail
}
// return a rejection for a failure
function failedCheck() {
return $q.reject();
}
// ------ DOCUMENT HANDLING ------
// update document but if errors occur recurse qUpdate until either complete or retries exhausted
function update(doc) {
var counter = 0;
return $q.when(qUpdate(doc,counter));
}
// this routine works for both new and existing documents
function qUpdate(doc,counter) {
return db.put(doc)
.then(function() {
console.log('success - new document');
})
.catch(function(e) {
console.log(e); // not a new document so try as a revision of existing document using _id to find
return db.get(doc._id)
.then(function(origDoc) {
doc._rev = origDoc._rev; // get document revision _rev
return db.put(doc,doc._id,doc._rev)
.then(function() {
console.log('success - revision of document');
})
.catch(function(e){
console.log(e); // log error for failure
});
})
.catch(function(e){
console.log(e); // log error before we take any other action
counter ++; // increment counter, so we can limit retries (5 by default)
if (counter< 5) {
switch (e.status) {
case 404:
delete doc._rev; // remove revision information so we can see if this works
return qUpdate(doc); // might be deleted so return revised document for retry
case 409:
return qUpdate(doc); // in conflict so try again
default:
try {
throw new Error("cannot save: " + doc._id); // cannot go any further so throw new error
} catch(err) {
console.log(err); // log error for failure
}
}
} else {
try {
throw new Error("cannot save" + doc._id); // cannot go any further so throw new error
} catch(err) {
console.log(err); // log error for failure
}
}
});
});
}
// update a document batch stored in an array
function updateBatch(docs) {
return $q.when(qUpdateBatch(docs));
}
// do the actual update of a batch
function qUpdateBatch(docs) {
db.bulkDocs(docs).then(function(res) {
for (var i=0; i < res.length; i++) {
if (res[i].status === 409) {
update(docs[i]); // in conflict so try this document separately
}
}
}).catch(function(e){
console.log(e); // log error
});
}
// get the document as an angular promise and deal with it in host routine
function getDoc(id) {
return $q.when(db.get(id));
}
// get all documents
function getAllDocs() {
return $q.when(db.allDocs({include_docs: true, attachments: false}));
}
// get a batch of documents between a start and end key
function getList(key) {
return $q.when(db.allDocs({startkey: key, endkey: key + '\uffff', include_docs: true, attachments: false}));
}
}
})();
In your main controller you would want to set the database:
$db.setLocalDB('yourDB');
Hope this is what you were looking for?
In my own data services module I have other functions for remote database, event listeners, remove, sync, compact, destroy and so on.

Resources