I am currently working on an HTML/JS App using Windows Azure Mobile Service.
I have two tables, one storing information about an attraction [attractionTable(attractionId, address,...)] and one keeping track of which user likes which attraction [favoriteAttractionTable(attractionId, userId, fav(bool))].
If the client wants to have a list of his favorite attractions there should only be one request to the server. On the server side I edited the read script of the favoriteAttractionTable to this:
function read(query, user, request) {
var sql =
"FROM routesTable rt, favoriteAttractionTable ft " +
"WHERE rt.id = ft.routeId;";
mssql.query(sql, {
success: function(results) {
request.respond(statusCodes.OK, results);
}});
}
In my JavaScript Code I am using the following request
function loadFavoriteAttractions(){
favTable = client.getTable("favoriteAttractionTable");
var query = favTable.where({
fav: true,
userId : 0
}).read().done(function (results) {
console.log(results);
}, function (err) {
alert("Error: " + err);
});
}
I basically get the information of all attractions that any user has added to his favorites but I want to modify the var sql in a way to receive only the ones related to the appropriate userId.
query.getComponents();
shows queryString: '((fav eq true) and (userId eq 0))' in my server script.
But I am wondering how I can access this information?!
request.parameters.fav
is supposedly undefined.
Any advice is highly appreciated :)
If you want to access request parameters in the scripts, your best bet is to use the custom query string parameters, something like the code below:
function loadFavoriteAttractions(){
favTable = client.getTable("favoriteAttractionTable");
var query = favTable.read({
fav: true,
userId : 0
}).done(function (results) {
console.log(results);
}, function (err) {
alert("Error: " + err);
});
}
Those parameters will be accessed via the request.parameters object on the server side.
If you're interested, here's more details: when you use the where method, you're passing some template object which will be converted into an OData $filter expression that is passed to the server. The server will then parse that and convert it into the appropriate SQL WHERE clause to be sent to the database. So your original code will send a request similar to this one (spaces will be replaced with %20, but left them here for clarity):
GET .../tables/favoriteAttractionTable?$filter=((fav eq true) and (userId eq 0))
As you found out, you can access it via the getComponents function, but at that point you'll have to parse the expression yourself to retrieve the values of the comparisons. If you want to access some values passed by the client, as I mentioned the easiest way is to pass them as "normal" query-string parameters. In the code I sent, the request that will be sent will be similar to
GET .../tables/favoriteAttractionTable?fav=true&userId=0
And those values you can retrieve from the request.parameters directly (the type of the values will be strings, so if you want to treat them as numbers of Boolean values you'll need to do the appropriate conversion).
Related
I want to access resources from a SQLite database table. I have one table for accounts, one for movies and one for reviews. The reviews-table is constructed like this:
CREATE TABLE IF NOT EXISTS reviews (
id INTEGER PRIMARY KEY,
authorId INTEGER,
movieId INTEGER,
review TEXT,
rating INTEGER,
FOREIGN KEY('authorId') REFERENCES 'accounts'('id'),
FOREIGN KEY('movieId') REFERENCES 'movies'('id')
)
What I want to do is that I want to be able to get all reviews, made by one author. But I also want to be able to get all reviews, made for the same movie. Below is my code for getting all reviews made by the same user/author. The code looks the same when getting the reviews based on the movie, with a few changes.
Both of them does what I want them to do. But of course only the one written first in the file are running.
const authorId = request.params.authorId;
const query = "SELECT * FROM reviews WHERE authorId = ?";
const values = [authorId];
db.all(query, values, function (error, review) {
if (error) {
response.status(500).end();
} else if (!review) {
response.status(404).end();
} else {
response.status(200).json(review);
}
});
});
The url will look the same no matter which of them I want running; http://localhost:3000/reviews/3. How can I differentiate the url so that they know which one should run?
I have tried to experiment with query strings, but I'm not sure how that works, and after hours of searching for something that worked on my code, I gave up.
I have also been thinking about using something like
app.use(function (request, response, next) {
if (request.method == "GET" && request.uri == "/reviews/:authorId") {
response.send("Hello World");
} else {
next;
}
});
This didn't work, and it didn't work if I tried to remove ":authorId" from the url either. The page just keeps loading.
So how do I solve this?
The most dynamic would be a single route /reviews and use the query string with the params like ?author=123 or ?movie=123, they can be combined like ?author=123&movie=123. As you want to return JSON the code will be used via API, so the pretty path is usually not as important as when it is a web-url. To make the implementation effective, most people use a function where you can drop the query object in and get the where-clause, or use an ORM.
In express, when you have routers like '/reviews/:authorId' and then '/reviews/:movieId', then the second one will never be called, because the first one will always match. That is something to be careful about when organizing your express routes.
I am retrieving data from a SharePoint list using JavaScript as below.
$().SPServices({
operation: 'GetListItems',
async: false,
listName: listName,
CAMLViewFields: '<ViewFields></ViewFields>',
completefunc: function (xData, status) {
if (status === 'success') {
// I work with the data in "$(xData.responseXML).find('z\\:row, row')"
} else {
console.log('\n Status is ' + status + '\n And data is ' + xData);
}
}
});
However, I need to give the list read access to anonymous users for the above solution to work. Is there a way to use JavaScript to retrieve data from SharePoint list and also keep the SharePoint list permission private for anonymous users?
No you can't. Client-side script uses current user permission to access the list so it's impossible to query a private list. But you could:
create a new list (with columns you need) and use MS Flow/Workflow to sync between 2 lists, then query on that list. Of course, the new list needs to be public.
develop a web api. In this web api, you can use another account (or client id/client secret) to query data from the sharepoint list. From client-side script, you query data from this api.
So I am trying to make a live search feature where a user can search for other users based on username and the relevant results will be shown on the webpage. So far, I have only come across resources that show how to do this for PHP and MySQL. How can this be achieved for Node.js and MongoDB? I'm using socket.io in my project, could this be used at all?
Thanks for the help, and if any of my code is needed, just let me know!
Basically, you would watch when the user writes in the username input field( using the keyup event) and send the value of the input field to the server using socket.io, on the server, when you receive the value in the event you will do a query on the database(model.findOne in mongoose) with that value and return the user if he exists. The key here is to make the database do an index on the username for a faster search by making the username field unique in mongoose or by creating a new index manually.
Example:
Frontend with jquery:
$(document).ready(function() {
var username = $('#username');
username.keyup(function() {
var value = username.val();
socket.emit('find_user', value);
});
});
socket.on('find_user_result', function(user) {
// treat result here
});
Backend with mongoose:
socket.on('find_user', function(value) {
User.findOne({username: value}, function(err, user) {
if (err) throw err;
if (!user) socket.emit('find_user_result', {});
else socket.emit('find_user_result', user);
});
})
In your requirement, it doesn't depend much on which backend to use.
On the backend just create a rest API to handle the search request (if you want to use NodeJS, you can refer this article https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4).
On the frontend, you can use just XHR request to make live search, no need socket. Each time user type on an input, detect the input change event and send the search request to the backend api (you can do it by just pure javascript XHR request, or use ajax module in JQuery ...), fetch the result from response, print to the screen.
After you can achieve this, you can improve your search performance on the frontend by limiting request in amount of time (not sending request each time use press a key, but after an amount of time, example each 200ms, this technique call "debounce").
I am trying to send a push notification using cloud code to targeted channels. The Object is called Prayers. When someone saves Prayers, it is supposed to send a push notification to certain channels, if the new data in Prayers was not made anonymously. Prayers has a key of 'Anonymous' in it that is boolean. So, I have cloud code set up like this, in an effort that if the boolean value is false, it sends, it, but if it is true, it won't send the push. The issue now is that it is sometimes sending the Push through 2 times on a non-anonymous post.
Parse.Cloud.afterSave("Prayers", function(request) {
var firstName = request.object.get('FirstName');
var lastName = request.object.get('LastName');
var userId = request.object.get('UserId');
var anonymous = request.object.get('Anonymous');
var anonymousString = anonymous.toString
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('channels', userId);
if (anonymous == false) {
Parse.Push.send({
where: pushQuery, // Set our Installation query
data: {
alert: firstName + " " + lastName + " " + "just added a prayer request."
}
}, {
success: function() {
// Push was successful
},
error: function(error) {
throw "Got an error " + error.code + " : " + error.message;
}
});
}
});
At first glance there doesn't seem anything wrong with your function, but since you always try to send a push notification after a prayer has been saved, are you sure you're not saving the object twice? That could be the reason why the afterSave is invoked twice.
One of the things I also once ran into was, that I had 2 pieces of cloud code
First one would modify an object when I tried to save it.
Second one was that I would do a push after saving the object.
In my code where I modified the object during the save process, I saved the modified object, which resulted in my Parse.Cloud.afterSave being fired twice for the same object
Server Side
Update reg_id by UUID when device registration on server.
Delete by reg_id which have return a canonical_id in the response after send a push.
Periodically send fake push using dry_run and do the same things as 2.
Client Side
Send message_id within payload, and save it in sqlite DB. And device will know that it has received it or not.
I have meteor method that does an insert.
Im using Regulate.js for form validation.
I set the game_id field to Meteor.uuid() to create a unique value that I also route to /game_show/:game_id using iron router.
As you can see I'm logging the details of the game, this works fine. (image link to log below)
file: /lib/methods.js
Meteor.methods({
create_game_form : function(data){
Regulate.create_game_form.validate(data, function (error, data) {
if (error) {
console.log('Server side validation failed.');
} else {
console.log('Server side validation passed!');
// Save data to database or whatever...
//console.log(data[0].value);
var new_game = {
game_id: Meteor.uuid(),
name : data[0].value,
game_type: data[1].value,
creator_user_id: Meteor.userId(),
user_name: Meteor.user().profile.name,
created: new Date()
};
console.log("NEW GAME BEFORE INSERT: ", new_game);
GamesData.insert(new_game, function(error, new_id){
console.log("GAMES NEW MONGO ID: ", new_id)
var game_data = GamesData.findOne({_id: new_id});
console.log('NEW GAME AFTER INSERT: ', game_data);
Session.set('CURRENT_GAME', game_data);
});
}
});
}
});
All of the data coming out of the console.log at this point works fine
After this method call the client routes to /game_show/:game_id
Meteor.call('create_game_form', data, function(error){
if(error){
return alert(error.reason);
}
//console.log("post insert data for routing variable " ,data);
var created_game = Session.get('CURRENT_GAME');
console.log("Session Game ", created_game);
Router.go('game_show', {game_id: created_game.game_id});
});
On this view, I try to load the document with the game_id I just inserted
Template.game_start.helpers({
game_info: function(){
console.log(this.game_id);
var game_data = GamesData.find({game_id: this.game_id});
console.log("trying to load via UUID ", game_data);
return game_data;
}
});
sorry cant upload images... :-(
https://www.evernote.com/shard/s21/sh/c07e8047-de93-4d08-9dc7-dae51668bdec/a8baf89a09e55f8902549e79f136fd45
As you can see from the image of the console log below, everything matches
the id logged before insert
the id logged in the insert callback using findOne()
the id passed in the url
However the mongo ID and the UUID I inserted ARE NOT THERE, the only document in there has all the other fields matching except those two!
Not sure what im doing wrong. Thanks!
The issue is your code is running on the client side (or at least it looks like from the screenshot).
In meteor, Meteor.methods that run on the client side are simulation stubs. What this means is you put stuff in there that creates 'fake' data so that you can avoid the user feeling latency. This is because it would take 1-4 seconds for the server to reply with what was actually inserted in the database. This isn't really an issue though.
The reason this causes you trouble is the method is run twice (one on the server and one on the client), so it generates two different Meteor.uuids since they are random. So this is why you have the inconsistency. What you see is the 'fake' one initially, then the server sends down the real one.
This is how Meteor makes it look like data has been inserted instantly, even though its not fully yet inserted.
To fix this get rid of the the .method you have on the client so that you only have one running on the server. You would need to get the game_id from the server though and not from the client.
If you want to keep the latency compensation, pass the Meteor.uuid in data like you do your other form data. This way the game_id will be consistent on both the server and client.