I am new to node.js and callbacks. I have to search in 4 different tables depending on user's search configurations. There could be max 4 search queries. For example:
Table-1
city
Table-2
country
Table-3
diet
Table-4
product
If user's configuration has city and country name then I need to search in Table-1 and Table-2. If I find any relevant information in any table, I need to return true and stop checking rest of the tables. If I cannot find relevant information in any table, I need to return false.
Mysql connector: "mysql": "^2.13.0"
Pseudo code:
function search(searchTerm, type, cb) {
if (type=="city") {
searchDB(searchTerm, "city", "fct", function (result) {
if (result == true) cb(result)
});
}
if (type=="country") {
searchDB(searchTerm, "country", "fcy", function (result) {
if (result == true) cb(result)
});
}
if (type=="diet") {
searchDB(searchTerm, "diet", "fdt", function (result) {
if (result == true) cb(result)
});
}
if (type=="product") {
searchDB(searchTerm, "product", "fpt", function (result) {
if (result == true) cb(result)
});
}
}
function searchDB(searchTerm, tableName, fieldName, cb) {
var qryParams;
var qry = 'SELECT * from ?? where ??=?';
qryParams = [tableName, fieldName, searchTerm];
qry = mysql.format(qry, qryParams);
connection.query(qry, function (error, results, fields) {
if (error) throw error;
if (results == "") {
return cb(false);
} else {
return cb(true);
}
});
}
In your situation you should use Promise.race() function. Not posting entire example here because a great and complete example is shown on MDN page.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
Promise.race([p3, p4]).then(function(value) {
console.log(value); // "three"
// p3 is faster, so it resolves
}, function(reason) {
// Not called
});
EDIT. Just realized you might not be using promises... Have a read about them, Promises are intended to fight the dreaded callback hell.
Related
I´ve downloaded the Forge Design Automation sample from the following link:
https://learnforge.autodesk.io/#/tutorials/modifymodels
But the downloable code example is not working fine. When any async method who involves the DesignAutomation API is called I get -> Value cannot be null. (Parameter 'ForgeConfiguration.ClientId'). So, I would like to know how it works and how I can set the ClientId in the ForgeConfiguration class or else if I making something else wrong. I attach a fragment of code where I get the error.
[HttpGet]
[Route("api/forge/designautomation/engines")]
public async Task<List<string>> GetAvailableEngines()
{
List<string> allEngines = new List<string>();
try
{
dynamic oauth = await OAuthController.GetInternalAsync();
// define Engines API
string paginationToken = null;
while (true)
{
Page<string> engines = await _designAutomation.GetEnginesAsync(paginationToken);
allEngines.AddRange(engines.Data);
if (engines.PaginationToken == null)
break;
paginationToken = engines.PaginationToken;
}
allEngines.Sort();
}
catch (Exception error) {
throw error;
}
return allEngines; // return list of engines
}
And the call of the method:
function prepareLists() {
list('engines', 'api/forge/designautomation/engines');
}
function list(control, endpoint) {
$('#' + control).find('option').remove().end();
jQuery.ajax({
url: endpoint,
success: function (list) {
if (list.length === 0)
$('#' + control).append($('<option>', { disabled: true, text: 'Nothing found' }));
else
list.forEach(function (item) { $('#' + control).append($('<option>', { value: item, text: item })); })
}
});
}
Did you forget to set the Forge App Keys in the Environment Variables of your project, check the page at https://learnforge.autodesk.io/#/environment/setup/netcore_da
Below is a service I wrote to try and sync data from my remote couchdb location to a device. However, the biggest issue I have is only wanting to retrieve data that has a type: document if it's within a timestamp period.
Right now, I am pretty sure it grabs EVERY document and then filters it out.
I'd like to filter it out first before it comes through because I have a LOT of documents.
Does anyone know how I can accomplish is?
.service("$pouchDB", ["$rootScope", "$q", "$cordovaNetwork", "$state", function($rootScope, $q, $cordovaNetwork, $state) {
var self = this;
self.db = new PouchDB("IDHERE", {auto_compaction: true});
self.remoteToDevice = function(s) {
var remote_db = new PouchDB('https://SOMETHING#URL/IDHERE', {ajax: {timeout: 180000}});
return self.db.replicate.from(remote_db, {
filter: function (doc) {
if(doc.type == 'document')
if(doc.timestamp >= (Math.floor(Date.now() / 1000)-2419200))
return doc;
else return doc;
}
}).on('complete', function () {
console.log("Remote to Device - Success");
})
.on('error', function (err) {
console.log("Remote to Device - Error", JSON.stringify(err));
return err;
});
}
}
EDIT:
Thanks to Alexis, here is a solution I believe works
New remoteToDevice filter function
{
filter: "filters/device",
query_params: {
"timestamp": (Math.floor(Date.now() / 1000)-2419200)
}
}
Filter function in couchdb
"filters": {
"device": "function(doc, req) {
if(doc.type == \"document\") {
if(doc.timestamp >= req.query.timestamp) return true;
else return false;
}
else return true;
}"
}
You should define a filter function in a design document in CouchDB.
When replicating, you will need to specify the filter name.
Full documentation here: https://pouchdb.com/api.html#filtered-replication
I'm using babel with decorator stage:0 support in my flux fluxible js project, and I want to use an authenticated decorator for my service api modules to check for a valid user session.
Googling around, there seems to be several posts that explain different variations but couldn't find one definitive docs or instructionals.
Here's what I tried so far, I know that my parameters for the authenticated function are incorrect, and not sure if I need to implement a class for my module rather than just using the exports object.
The part that I couldn't find the docs for is how to implement the decorator itself - in this case something that takes the req parameter the decorated function will receive and checking it.
// how do I change this method so that it can be implemented as a decorator
function checkAuthenticated(req) {
if (!req.session || !req.session.username)
{
throw new Error('unauthenticated');
}
}
module.exports = {
#checkAuthenticated
read: function(req, resource, params, serviceConfig, callback) {
//#authenticated decorator should allow me to move this out of this here
//checkAuthenticated(req);
if (resource === 'product.search') {
var keyword = params.text;
if (!keyword || keyword.length === 0) {
return callback('empty param', null);
} else {
searchProducts(keyword, callback);
}
}
}
};
class Http{
#checkAuthenticated
read(req, resource, params, serviceConfig, callback) {
if (resource === 'product.search') {
var keyword = params.text;
if (!keyword || keyword.length === 0) {
return callback('empty param', null);
} else {
this.searchProducts(keyword, callback);
}
}
}
searchProducts(keyword, callback) {
callback(null, 'worked');
}
}
function checkAuthenticated(target, key, descriptor) {
return {
...descriptor,
value: function(){
console.log(arguments);
const req = arguments[0];
if (!req.session || !req.session.username) {
throw new Error('unauthenticated');
}
return descriptor.value.apply(this, arguments);
}
};
}
let h = new Http();
h.read(
{ session: { username: 'user' } },
'product.search',
{ text: 'my keywords' },
null,
function(err, result) {
if (err) return alert(err);
return alert(result);
}
);
See jsbin http://jsbin.com/yebito/edit?js,console,output
I am using sqlite and javascript for phoneGap. I am trying get 'lookMatchEvent(...)' function's returned value(true or false) and do something by checking result in addValueToDB(..) function. but's lookMatchEvent(...) function is not returning value immediately. Right now it's only returning false value as default. sql statements are absolutely fine, I think it's a problem with callback value. It will be great if anyone can fix this below coding.. :) thanks a lot in advance...
function AddValueToDB(sportName, location, dateTime, team, teamOpp) {
if(lookMatchEvent(sportName, location, dateTime, team, teamOpp)) {//adding new row to database}
else {donot add data}
}
function lookMatchEvent($sportName, $location, $dateTime, $team, $teamOpp) {
db.transaction(function(transaction) {
transaction.executeSql("SELECT * from sport where sportName='"+$sportName+"' and location='"+$location+"' and dateTime='"+$dateTime+"' and team='"+$team+"' and teamOpp='"+$teamOpp+"';",
[],
function(transaction, result) {
if (result != null && result.rows != null)
{
if (result.rows.length > 0) {
return false;
}
return false;
}
else
{
return true;
}
},errorHandler);
},errorHandler,nullHandler);
}
The callback functions run asynchronously, and a return returns only from that function.
You must split the code that should run afterwards into a separate function, and call that from the callback:
function AddValueToDB(sportName, location, dateTime, team, teamOpp) {
lookMatchEvent(sportName, location, dateTime, team, teamOpp);
}
function AddValueToDB_part2(result) {
if (result) {
...
} else {
...
}
}
function lookMatchEvent(...) {
db.transaction(...
...
function(transaction, result) {
if (result != null && result.rows != null)
{
if (result.rows.length > 0) {
AddValueToDB_part2(false);
}
AddValueToDB_part2(false);
}
else
{
AddValueToDB_part2(true);
}
}
...
);
}
If the lookMatchEvent function must not know from where it is called (because it's called from multiple places), you can give the second function as a parameter:
function AddValueToDB(sportName, location, dateTime, team, teamOpp) {
lookMatchEvent(sportName, location, dateTime, team, teamOpp,
function(result) {
if (result) {
...
} else {
...
}
});
}
function lookMatchEvent(..., my_callback) {
db.transaction(...
...
function(transaction, result) {
if (result != null && result.rows != null)
{
if (result.rows.length > 0) {
my_callback(false);
}
my_callback(false);
}
else
{
my_callback(true);
}
}
...
);
}
Your callback is the problem.
function AddValueToDB(sportName, location, dateTime, team, teamOpp) {
function doActionOnResult(transaction, result){
//Do your action here
if (result != null && result.rows != null)
{
if (result.rows.length > 0) {
return false;
}
return false;
}
else
{
return true;
}
}
lookMatchEvent(sportName, location, dateTime, team, teamOpp, doActionOnResult)
}
function lookMatchEvent($sportName, $location, $dateTime, $team, $teamOpp, callback) {
db.transaction(function(transaction) {
transaction.executeSql("SELECT * from sport where sportName='"+$sportName+"' and location='"+$location+"' and dateTime='"+$dateTime+"' and team='"+$team+"' and teamOpp='"+$teamOpp+"';",
[],
doActionOnResult,
errorHandler);
},errorHandler,nullHandler);
}
I've got the following.
var lookupInit = function () {
http.get('api/employmenttype', null, false)
.done(function (response) {
console.log('loaded: employmenttype');
vm.lookups.allEmploymentTypes(response);
});
http.get('api/actionlist', null, false)
.done(function (response) {
console.log('loaded: actionlist');
vm.lookups.allActionListOptions(response);
});
http.get('api/company', null, false)
.done(function (response) {
console.log('loaded: company');
vm.lookups.allCompanies(response);
});
//... x 5 more
return true;
};
// somewhere else
if (lookupInit(id)) {
vm.userInfo.BusinessUnitID('0');
vm.userInfo.BuildingCode('0');
if (id === undefined) {
console.log('api/adimport: latest');
http.json('api/adimport', { by: "latest" }, false).done(viewInit);
}
else if (id !== undefined) {
console.log('api/adimport: transaction');
http.json('api/adimport', { by: "transaction", TransactionId: id }, false).done(viewInit);
}
} else {
console.log('User info init failed!');
}
The following "http.get('api/employmenttype', null, false)" means i set async to false.
I'm aware that this is probably inefficient. And i'd like to have all the calls load simultaneously.
The only problem is if i don't have them set to async false, the second part of my code might execute before the dropdowns are populated.
I've tried a couple of attempts with Jquery Deferreds, but they have resulted in what i can only describe as an abortion.
The only thing i'm looking to achieve is that the lookup calls finish before the adimport/second part of my code, in any order.... But having each call wait for the one before it to finish EG: async, seems like the only solution I'm capable of implementing decently ATM.
Would this be an appropriate place for deferred function, and could anyone point me into a direction where i could figure out how to implement it correctly, as I've never done this before?
You can use $.when to combine multiple promises to one that resolves when all of them have been fulfilled. If I got you correctly, you want
function lookupInit() {
return $.when(
http.get('api/employmenttype').done(function (response) {
console.log('loaded: employmenttype');
vm.lookups.allEmploymentTypes(response);
}),
http.get('api/actionlist').done(function (response) {
console.log('loaded: actionlist');
vm.lookups.allActionListOptions(response);
}),
http.get('api/company').done(function (response) {
console.log('loaded: company');
vm.lookups.allCompanies(response);
}),
// … some more
);
}
Then somewhere else
lookupInit(id).then(function(/* all responses if you needed them */) {
vm.userInfo.BusinessUnitID('0');
vm.userInfo.BuildingCode('0');
if (id === undefined) {
console.log('api/adimport: latest');
return http.json('api/adimport', {by:"latest"})
} else {
console.log('api/adimport: transaction');
return http.json('api/adimport', {by:"transaction", TransactionId:id});
}
}, function(err) {
console.log('User info init failed!');
}).done(viewInit);
In the Jquery API I've found this about resolving multiple deferreds:
$.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1, a2){
/* a1 and a2 are arguments resolved for the
page1 and page2 ajax requests, respectively.
each argument is an array with the following
structure: [ data, statusText, jqXHR ] */
var data = a1[0] + a2[0]; /* a1[0] = "Whip", a2[0] = " It" */
if ( /Whip It/.test(data) ) {
alert("We got what we came for!");
}
});
Using this with your code:
var defer = $.when(
$.get('api/employmenttype'),
$.get('api/actionlist'),
$.get('api/company'),
// ... 5 more
);
defer.done(function (arg1, arg2, arg3 /*, ... 5 more*/) {
vm.lookups.allEmploymentTypes(arg1[0]);
vm.lookups.allEmploymentTypes(arg2[0]);
vm.lookups.allEmploymentTypes(arg3[0]);
// .. 5 more
vm.userInfo.BusinessUnitID('0');
vm.userInfo.BuildingCode('0');
if (id === undefined) {
console.log('api/adimport: latest');
http.json('api/adimport', { by: "latest" }, false).done(viewInit);
} else if (id !== undefined) {
console.log('api/adimport: transaction');
http.json('api/adimport', { by: "transaction", TransactionId: id }, false).done(viewInit);
}
});
You can use the defer of the $.when() inside an other $.when(), so if the json calls are not dependant on the first calls you can add them in a an onther defer.