Azure mobile service - get row(s) based on matching string/substring value - javascript

I am trying to read results from JavaScript azure mobile service and I want to return items with a specific values. I am using getTable(‘’).where.(‘’).read(‘’) to check if one of the returned json value match a specific pattern as shown in this post:
Here is my client side script:
function getSP() {
var spUser = client.getTable("User").where(function (contains) {
return this.extraname.indexOf(contains) > 0;
}, "Eyad").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});}
And the request URL generated from client:
https://XYZ.azure-mobile.net/tables/User?$filter=(indexof(extraname,'Eyad') gt 0)
But the code above return an empty [] object form the service, while performing the same operation without the where() check clearly returns my intended value:
What am I doing wrong? How can I return the row(s) where the returned "extraname" contains the substring "Eyad"?
NOTE: I also have a custom read script on the service side, and you can see the "extraname" value is hardcoded for testing purposes:
function read(query, user, request) {
request.execute({
success: function(results) {
var now = new Date();
results.forEach(function(item) {
console.log(item.userjsondata);
item.extraname = "Eyad";
});
request.respond(); //Writes the response
}
});
}

If you're generating a new column dynamically, then there's no way to - directly - use a $filter clause to filter the results based on that value. Notice that you can write arbitrary code to calculate that value, so the mobile service runtime has no way to know what value it will end up generating, and cannot perform a filter based on that.
There are a couple of workarounds for your solution: if possible, you can send a where clause with the same expression that you use to generate the value. In some cases the service will accept that expressions in the $filter clause as well. That has the drawback that you'll end up with the same logic in two different places, and there's a big chance that you'll change one and end up forgetting to change the other.
Another alternative is to pass the parameter for which you want to query the generated property not in the $filter parameter (i.e., don't use the where function, but pass the parameters inside the read call. Those parameters will be passed to the read script in the request.parameters object, and you can add your logic to filter based on that value after you're done reading from the database (see below).
Client:
var spUser = client.getTable("User").read({mustContain: "Eyad").done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});}
Service:
function read(query, user, request) {
var mustContain = request.parameters.mustContain;
request.execute({
success: function(results) {
var now = new Date();
var filteredResults = [];
results.forEach(function(item) {
console.log(item.userjsondata);
item.extraname = "Eyad";
if (item.extraname.indexOf(mustContain) >= 0) {
filteredResults.push(item);
}
});
request.respond(200, filteredResults); //Writes the response
}
});
}

change your comparison from this:
return this.extraname.indexOf(contains) > 0;
to this:
return this.extraname.indexOf(contains) >= 0;
A matched string can be (in your case, always) found in the first index. Therefore you have to use greater than OR equal to operator to handle that case.

Related

Asynchronous data retrieving and rendering in ExtJS with Ajax

so I have this situation:
renderer: function(value, grid, record) {
var testAjax = function(callback) {
Ext.Ajax.request({
url: appConfig.baseUrl + '/api/users/' + record.getData().id + '/jobRoles',
method: 'GET',
success: function(result) {
callback(result)
};
});
};
return testAjax(function(result) {
try {
result = JSON.parse(result.responseText);
} catch(e) {
return '';
}
result = result.data;
var roles = _.map(result, function(jRole) {
console.log(jRole);
return jRole.name;
}).join(',');
console.log("Roles: ", roles);
return roles;
});
}
What I wanted to achieve is that when I have to render a particular field, I make a call to my Loopback endpoint, retrieve some data about a relation, map it using a "," character and return the joined string in order to view it.
However, I think I have a few problem with callbacks here as I don't see the result at all, as if the function is returning before the callback is called (thus showing nothing instead of what I retrieved from the server).
I tried to look here and there, and this is the best I came up with.
How can I return to the parent function the "roles" variable? How do I properly set up my callbacks?
Regards
You cannot and should not use the renderer with load operations and asynchonous callbacks. The renderer can be called dozens of times for the same record, if you filter or sort or just refresh the grid view. What you want to do is get all the information required for display in the grid in a single call. Data you cannot get in the single call should not be shown in the grid. You don't want to call the endpoint 1000 times for 1000 records, because even if each call needs only 60ms, that's a full minute.
That said, if you really have to, because you cannot change the endpoints and the roles have to be displayed, you can do as follows:
dataIndex: 'MyTempRoles',
renderer: function(value, grid, record) {
if(value) return value; // show the loaded value if available
else { // no value loaded -> load value
Ext.Ajax.request({
url: appConfig.baseUrl + '/api/users/' + record.getData().id + '/jobRoles',
method: 'GET',
success: function(result) {
try {
result = JSON.parse(result.responseText);
result = result.data;
var roles = _.map(result, function(jRole) {
console.log(jRole);
return jRole.name;
}).join(',');
record.set("MyTempRoles", roles || " "); // put the loaded value into the record. This will cause a grid row refresh, thus a call to the renderer again.
} catch(e) {
}
}
});
}
}
This will call the backend in the first call to the renderer, and asynchronously fill the displayed record's temp variable. When the temp variable is filled, the renderer will then display the value from the temp variable automatically.

Javascript function doesn't return query result

I am trying to figure out why one of my queries won't return the value from a query...my code looks like this:
var client = new pg.Client(conString);
client.connect();
var query = client.query("SELECT count(*) as count FROM sat_scores")
// Don't use demo key in production. Get a key from https://api.nasa.gov/index.html#apply-for-an-api-key
function getNEO(callback) {
var data = '';
query.on('rows', function(rows) {
console.log("Row count is: %s", rows[0].count)
data += rows[0].count;
});
query.on('end', function() {
callback(data);
});
}
with that, getNEO returns a blank...but if I set var data = '4', then getNEO returns 4....the query should return 128 but it just returns a blank...
First of all, getNEO() doesn't return anything - I'm operating on the assumption that you call getNEO() exactly once for your query, and pass in a callback to handle the data, and that callback is what's not getting the appropriate data?
My typical recommendation for troubleshooting things like this is to simplify your code, and try and get really close to any example code given (for instance):
var client = new pg.Client(conString);
// define your callback here, in theory
client.connect(function (err) {
if (err) throw err;
var query = client.query("SELECT count(*) as count FROM sat_scores"),
function(err, result) {
if (err) throw err;
console.log(result.rows.length);
}
);
});
... I'm doing a couple things here you'll want to note:
It looks like the client.connect() method is asynchronous - you can't just connect and then go run your query, you have to wait until the connection is completed, hence the callback. Looking through the code, it looks like it may emit a connect event when it's ready to send queries, so you don't have to use a callback on the connect() method directly.
I don't see a data event in the documentation for the query object nor do I see one in the code. You could use the row event, or you could use a callback directly on the query as in the example on the main page - that's what I've done here in the interest of simplicity.
I don't see the count property you're using, and row[0] is only going to be the first result - I think you want the length property on the whole rows array if you're looking for the number of rows returned.
I don't know if you have a good reason to use the getNEO() function as opposed to putting the code directly in procedurally, but I think you can get a closer approximation of what you're after like this:
var client = new pg.Client(conString);
// define your callback here, in theory
client.connect();
function getNEO(callback) {
client.on('connect', function () {
var query = client.query("SELECT count(*) as count FROM sat_scores"));
query.on('end', function(result) {
callback(result.rowCount);
});
});
}
... so, you can call your getNEO() function whenever you like, it'll appropriately wait for the connection to be completed, and then you can skip tracking each row as it comes; the end event receives the result object which will give you all the rows and the row count to do with what you wish.
so here is how I was able to resolve the issue....I moved the var query inside of the function
function getNEO(state, callback) {
var conString = "postgres://alexa:al#alexadb2.cgh3p2.us-east-1.redshift.amazonaws.com:5439/alexa";
var client = new pg.Client(conString);
client.connect();
var data = '';
var query = client.query("SELECT avg(Math) as math, avg(Reading) as reading FROM sat_scores WHERE State = '" + state + "'");
console.log("query is: %s", query);
query.on('row', function(row) {
console.log("Row cnt is: %s", row.math);
console.log("row is: " + row)
data += row;
});
console.log("made it");
query.on('end', function() {
callback(data);
});
}

How to get index of items return by limit & descending createAt

This is the first time I've used Parse, I'm loving it so far, reading and writing data is working.
I now want to do something seemingly simple, but in the context of Parse seems like a pain to implement and my google-fu is failing me.
When I find the items like this:
var query = new Parse.Query(CommentClass);
query.limit(2);
query.descending('createdAt');
query.find({
success: function(object) {
callback({
comments: object
});
},
error: function(object, error) {
console.log('there was an error');
}
});
I want to know what indexes of the returned items are in the total list. If my list has 5 items, this will return the last 2 created, but there's no way - without another request knowing the number of items in the list.
There is not an easy way to do it in Parse. One way is to keep a global index in a separate object. In every new comment you need to get this global index, increment it, and put it into the comment. But it can get messy in case of comment deletions. Here is an example assuming no comment deletion:
SequenceForComment.js
// A class called SequenceForComment. Only one row.
// Only one integer property called 'sequence'.
// You can create the row by using the Parse dashboard in the beginning.
var SequenceForComment = Parse.Object.extend("SequenceForComment");
function getSequenceForComment(callback) {
var query = new Parse.Query(SequenceForComment);
return query.first().then(function (object) {
// https://parse.com/docs/js/api/classes/Parse.Object.html#methods_increment
//Increment is atomic.
object.increment('sequence');
return object.save();
}).then(function (object) {
callback(object.get('sequence'));
}, function (error) {
console.log(error);
callback(undefined);
});
}
module.exports = {
getSequenceForComment: getSequenceForComment
};
main.js
var SequenceModule = require("cloud/SequenceForComment.js");
Parse.Cloud.beforeSave("Comment", function(request, response) {
var comment = request.object;
// First time this comment will be saved.
// https://parse.com/docs/js/api/classes/Parse.Object.html#methods_isNew
if (comment.isNew()) {
// Get a sequence/index for the new comment
SequenceModule.getSequenceForComment(function(sequence) {
if (sequence) {
comment.set("sequence", sequence);
response.success();
} else {
response.error('Could not get a sequence.');
}
});
} else { // Not a new save, already has an index
response.success();
}
});

How to fetch an object in Parse Cloud Code

I am working on a parse cloud code function which performs a query and filters the results afterwards. These are my first lines of code written in JavaScript, so I have no clue how to solve the following problem.
The problem is, that my filter predicate needs some elements stored in the someArray variable. All elements of someArray aren't fetched yet. But fetching an an Parse.Object is a asynchronous call, so I have no chance to return trueor false expected by filter().
How can I solve this problem?
Or I am misinterpreting the fact, that when I don't fetch the arrayElement
console.log("arrayElement with name: ".concat(typeof(arrayElement), arrayElement.get("name")));
prints
arrayElement with name:objectundefiend
although I know that Object represented by arrayElment has a name-column which is always defined?
//The cloud code
Parse.Cloud.define("search", function(request, response) {
var query = new Parse.Query("Location");
query.withinKilometers("gps", request.params.searchLocation, request.params.searchRadius / 1000);
query.find({
success: function(results) {
// results is an array of Parse.Object.
var locations = results.filter(function(location) {
console.log("Location with name: ".concat(location.get("name")));
var someArray = location.get("someArray");
if (someArray instanceof Array) {
console.log("The array of this location has ".concat(someArray.length, " elements."));
someArray.forEach(function(arrayElement) {
arrayElement.fetch().then(
function(fetchedArrayElement) {
// the object was fetched successfully.
console.log("arrayElement with name: ".concat(typeof(fetchedArrayElement), fetchedArrayElement.get("name")));
if (menuItem) {};
return true;
},
function(error) {
// the fetch failed.
console.log("fetch failed");
});
});
}
});
response.success(locations);
},
error: function(error) {
// error is an instance of Parse.Error.
response.error(error);
}
});
});
some useful links:
Parse JavaScript SDK API
Parse Cloud Code Guide
If I'm reading this right, you've got an array column of Parse Objects. You should use the include method on your query so that the objects are fetched in the initial query.
query.include('someArray');
I don't think you'll want to use a filter, and should take a look at the Promises documentation here: https://parse.com/docs/js_guide#promises
You're right that since it's asynchronous, you need to wait for everything to be done before calling response.success which doesn't currently happen in the code. Promises and defining your own async functions that use Promises is a great way of chaining functionality and waiting for groups of functions to complete before going forward.
If all you wanted to do what include that column, the whole thing should just be:
Parse.Cloud.define("search", function(request, response) {
var query = new Parse.Query("Location");
query.include('someArray');
query.withinKilometers("gps", request.params.searchLocation, request.params.searchRadius / 1000);
query.find().then(function(results) {
response.success(locations);
}, function(error) {
response.error(error);
});
});

How to return the selected values from SQLite statement?

I am developing an application for iPhone but I write JavaScript. I store some information (the id and the name of an item) in the local database and now I need to get that information back so that I can use it. Unfortunately, the database returns to me undefined value but if I alert the value before the return statement, I get it correctly. My code is below:
function DB() {
myDatabase.transaction(function (transaction) {
transaction.executeSql("SELECT * FROM myTable WHERE id = ?", [idNum],
function (transaction, resultSet) {
var i = 0;
var currentRow = resultSet.rows.item(i);
return currentRow.name;
},
function (transaction, error) {
alert('error:' + error.message);
}
);
})
}
What am I doing wrong?
The transaction method you are using does not return a value. Instead it passes it to a result function. Returning a result from the result function does nothing. You have to use the result of the query within the result function.
Are you sure that the data is in the database?
If that is all that you need to store you may be better off using localStorage.
http://diveintohtml5.ep.io/storage.html

Categories

Resources