I have a social app for which I am trying to create a friend activities feed using Azure Sql Server.
I have 3 tables I want to select from:
Songs
-createdAt
-id
-userId
-trackName
-etc
Comments
-createdAt
-id
-userId
-songId
-text
Likes
-createdAt
-id
-userId
-songId
I have the users that the current user is following stored in an array named 'follows'.
How do I go about selecting the 40 most recent items from those 3 tables where userId in each table is in the follows array?
Edit:
function getActivities(userId) {
var deferred = Q.defer();
var follows = [];
getFollowing(userId).then(function (results) {
follows.push(userId);
_.each(results, function (user) {
follows.push(user.toUserId);
});
return;
}).then(function () {
var stringified = "'" + follows.join("','") + "'";
var queryString = "SELECT * FROM comments, songs, likes WHERE comments.userId IN (" + stringified + ") OR songs.userId IN (" + stringified +") OR likes.userId IN (" + stringified + ")";
var params = [];
return sqlQuery(queryString, params);
}).then(function (results) {
console.log('Activities: ', results);
deferred.resolve(results);
}, function (error) {
console.log('Error: ', error.message);
deferred.reject(error.message);
});
return deferred.promise;
}
Alright, so I dug into JOINS a little more and realized how easy it actually is once you wrap your head around it. Here is what I did to complete this:
var queryString = "SELECT TOP 50 follows.id AS followId, follows.toUserId AS followToUserId, follows.fromUserId AS followFromUserId, comments.text AS commentText, profiles.userId, profiles.username, profiles.name, profiles.profileImage, songs.trackId, songs.trackName, songs.artistName, songs.collectionName, songs.artworkUrl100, songs.caption, songs.id AS songId, activities.id AS activityId, activities.type AS activityType, activities.objectId AS activityObjectId, activities.parentType AS activityParentType, activities.parentId AS activityParentId, activities.__createdAt AS activityCreatedAt FROM activities ";
queryString += "INNER JOIN profiles ON (profiles.userId = activities.userId) ";
queryString += "LEFT JOIN songs ON (songs.id = activities.objectId AND activities.type = 'songs') OR (songs.id = activities.parentId AND activities.parentType = 'songs') ";
queryString += "LEFT JOIN comments ON (activities.type = 'comments' AND comments.id = activities.objectId) ";
queryString += "LEFT JOIN follows ON (activities.type = 'followed' AND activities.userid = follows.fromUserId) ";
queryString += "WHERE activities.userId IN (SELECT follows.toUserId AS userId FROM follows WHERE follows.fromUserId = ? AND follows.isFollowed = 'true') ";
queryString += "ORDER BY activities.__createdAt DESC";
var params = [userId];
mssql.query(queryString, params, {
success: function (results) {
_.each(results, function (result) {
//Remove columns with null or undefined values
for (var i in result) {
if (result[i] === null || result[i] === undefined) {
delete result[i];
}
}
});
response.send(200, results);
},
error: function (error) {
response.send(400, error.message);
}
});
Related
I am writing API which insert into a table with multiple rows, I am using UNNEST to make it work.
What I have done:
in js file:
api.post(PREFIX + '/class/insert', function (request) {
var db = pgp(dbconnect);
//Params
var data = request.body; //should be an array
var classes = [];
var starts = [];
var ends = [];
for (var i = 0; i < data.length; i++) {
classes.push(data[i].class_id);
starts.push(data[i].timestamp_start);
ends.push(data[i].timestamp_end);
}
const PQ = require('pg-promise').ParameterizedQuery;
var sql =
"INSERT INTO sa1.class(class_id, timestamp_start, timestamp_end) " +
"VALUES( "+
"UNNEST(ARRAY" + JSON.stringify(classes).replace(/"/g, "'") + "), " +
"UNNEST(ARRAY" + JSON.stringify(starts).replace(/"/g, "'") + "), " +
"UNNEST(ARRAY" + JSON.stringify(ends).replace(/"/g, "'") + ")"
const final_sql = new PQ(sql);
return db.any(final_sql)
.then(function (data) {
pgp.end();
return 'successful';
})
.catch(function (error) {
console.log("Error: " + error);
pgp.end();
});
}
Request body
[{
"class_id":"1",
"timestamp_start":"2017-11-14 14:01:23.634437+00",
"timestamp_end":"2017-11-14 15:20:23.634437+00"
}, {
"class_id":"2",
"timestamp_start":"2017-11-14 15:01:23.634437+00",
"timestamp_end": "2017-11-14 16:20:23.634437+00"
}]
When I run api in postman, I get the error is:
column "timestamp_start" is of type timestamp with time zone but
expression is of type text
Issue is obviously from ARRAY of string that I used in sql, my question is how to create ARRAY of timestamp for UNNEST, or any suggestion are appreciated.
Thanks
Never initialize the database inside the handler, see: Where should I initialize pg-promise
Never call pgp-end() inside HTTP handlers, it destroys all connection pools.
Use static ColumnSet type to generate multi-insert queries.
Do not return from db.any, there is no point in that context
You must provide an HTTP response within an HTTP handler
You are providing a confusing semantics for column class_id. Why is it called like that and yet being converted into a timestamp?
Never concatenate objects with strings directly.
Never concatenate SQL strings manually, it will break formatting and open your code to SQL injection.
Use Database methods according to the expected result, i.e. none in your case, and not any. See: https://github.com/vitaly-t/pg-promise#methods
Initialize everything needed only once:
const db = pgp(/*connection*/);
const cs = new pgp.helpers.ColumnSet([
'class_id',
{
name: 'timestamp_start',
cast: 'timestamp'
},
{
name: 'timestamp_end',
cast: 'timestamp'
}
], {table: {table: 'class', schema: 'sa1'}});
Implement the handler:
api.post(PREFIX + '/class/insert', request => {
const sql = pgp.helpers.insert(request.body, cs);
db.none(sql)
.then(data => {
// provide an HTTP response here
})
.catch(error => {
console.log('Error:', error);
// provide an HTTP response here
});
}
Many thanks to #JustMe,
It worked after casting array
var sql =
"INSERT INTO sa1.class(class_id, timestamp_start, timestamp_end) " +
"VALUES( "+
"UNNEST(ARRAY" + JSON.stringify(classes).replace(/"/g, "'") + "), " +
"UNNEST(ARRAY" + JSON.stringify(starts).replace(/"/g, "'") + "::timestamp[]), " +
"UNNEST(ARRAY" + JSON.stringify(ends).replace(/"/g, "'") + "::timestamp[])"
I've got a working script that grabs the last row of a Google sheet and pushes the info into Google contacts.
var ss = SpreadsheetApp.getActiveSheet(); //var emailRow = ss.getRange('F2:F').getValues();
var emailRowNum = ss.getLastRow(); //var emailRowNum = emailRow.filter(String).length + 1;
function email() {
var emailNew = ss.getRange(emailRowNum,6).getValue(); //var emailNew = ss.getRange("F"+emailRowNum).getValues();
return emailNew;}
function givenName() {
var fname = ss.getRange(emailRowNum,4).getValue();
return fname;}
function lastName() {
var lname = ss.getRange(emailRowNum,5).getValue();
return lname;}
function loc() {
var street = ss.getRange(emailRowNum,8).getValue();
var city = ss.getRange(emailRowNum,9).getValue();
return street + " " + city;}
function phone() {
var phone = ss.getRange(emailRowNum,7).getValue();
return phone;}
function notes() {
var date = ss.getRange(emailRowNum,1).getValue();
var work = ss.getRange(emailRowNum,2).getValue();
var photo = ss.getRange(emailRowNum,3).getValue();
var site = ss.getRange(emailRowNum,12).getValue();
var find = ss.getRange(emailRowNum,10).getValue();
var referrer = ss.getRange(emailRowNum,11).getValue();
return (date + "\n\n" + work + "\n\n" + photo + "\n\n" + site + "\n\n" + find + " " + referrer + "\n\n-- eom --\n\n");}
function create() {
var fname = givenName();
var lname = lastName();
var contact = ContactsApp.createContact(fname, lname, email());
var group = ContactsApp.getContactGroup('emf');
group.addContact(contact);
var contacts = ContactsApp.getContactsByName(fname + ' ' + lname);
var setaddress = contacts[0].addAddress(ContactsApp.Field.HOME_ADDRESS,loc());
var setphone = contacts[0].addPhone(ContactsApp.Field.MAIN_PHONE,phone());
for (var i in contacts) {
contacts[i].setNotes(notes());
}
}
I'd like to modify it so that instead of grabbing the last row, it checks a column for a (not) value. If value is not found, then update Google contacts with that row's information.
Currently, I'm getting a 'Range not found' error ...
function info(){
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getRange("N1:N").getValues();
for(var n=0;n<data.length;n++){
if(data[n-1] != 'done'){
var email = ss.getRange("F"+n).getValue(); // Range not found error
var fname = ss.getRange("D"+n).getValue();
var lname = ss.getRange("E"+n).getValue();
var city = ss.getRange("I"+n).getValue();
var street = ss.getRange("H"+n).getValue();
var phone = ss.getRange("G"+n).getValue();
var date = ss.getRange("A"+n).getValue();
var work = ss.getRange("B"+n).getValue();
var photo = ss.getRange("C"+n).getValue();
var site = ss.getRange("L"+n).getValue();
var find = ss.getRange("J"+n).getValue();
var referrer = ss.getRange("K"+n).getValue();
var contact = ContactsApp.createContact(fname, lname, email);
var group = ContactsApp.getContactGroup('emf');
group.addContact(contact);
var contacts = ContactsApp.getContactsByName(fname + ' ' + lname);
var setaddress = contacts[0].addAddress(ContactsApp.Field.HOME_ADDRESS,street + " " + city);
var setphone = contacts[0].addPhone(ContactsApp.Field.MAIN_PHONE,phone);
for (var i in contacts) {
contacts[i].setNotes(date + "\n\n" + work + "\n\n" + photo + "\n\n" + site + "\n\n" + find + " " + referrer + "\n\n-- eom --\n\n");}
}
}
}
1 is the first row using A1Notation with getRange(). The first iteration is trying to getValue() of F0. Changing the n to start at 1 and n <= data.length should get the ranges you are looking for.
...
for(var n=1;n<=data.length;n++){
if(data[n-1] == 'done'){
var email = ss.getRange("F"+n).getValue(); // Range not found error
...
edit: One thing to note the var data = ss.getRange("N1:N").getValues(); range is going to loop over all 1000 default rows. This may not be ideal if your data set is significantly smaller than 1000 rows.
Hi Im trying to dynamically ORDER BY my sqlite in angular. but it always says erro rcould not prepare statement.. and it redirect to my order string.. But when I manually set my ASC or DESC it works pretty well. My question is how can I set my string to my query
This is my js. The order_by_field is equal to the name and the order is equal to the ASC or DESC
//Sort Priority Ascending
$scope.sortAsc = function() {
sort_orderby('name', 'asc');
$scope.orderByPopover.hide();
};
//Sort Priority Descending
$scope.sortDesc = function() {
sort_orderby('name', 'desc');
$scope.orderByPopover.hide();
};
function sort_orderby(order_by_field, order) {
var query = "SELECT * FROM listJobs ORDER BY '" + order_by_field + "' '"+ order +"' ";
$cordovaSQLite.execute(db, query, [])
//If success
.then(function(data) {
offlineGetJobList();
console.log(data.rows)
},
function(err) {
console.error(err);
});
}
line
var query = "SELECT * FROM listJobs ORDER BY '" + order_by_field + "' '"+ order +"' ";
should be
var query = "SELECT * FROM listJobs ORDER BY " + order_by_field + " "+ order +" ";
Hi guys i'm working with angular $resource to make POST call. This is my FE function
$scope.showPrompt = function (ev) {
$scope.usernameSelected = [];
$scope.users.forEach(function (element) {
if (element.checked)
$scope.usernameSelected.push(element);
console.log($scope.usernameSelected);
});
var conferma = $mdDialog.prompt()
.title('Insert group name?')
.clickOutsideToClose(true)
//.textContent('Bowser is a common name.')
.placeholder('Group name')
.ariaLabel('Group name')
.targetEvent(ev)
.ok('Crea gruppo')
.cancel('Annulla');
$mdDialog.show(conferma).then(function (result) {
GroupService.group({}, {
creatore: $cookieStore.get('username'),
gruppo: result,
partecipanti: $scope.usernameSelected},
function (data) {
console.log("GRUPPO", data);
});
$scope.status = 'NOMEGRUPPO: ' + result + '.'; //inserito il nome gruppo
}, function () {
$scope.status = 'INSERT NOME GRUPPO';
});
};
This the GroupService:
var groupService = angular.module("groupService",['ngResource']);
groupService.factory("GroupService",['$resource',
function($resource){
var url = "";
return $resource("",{},{
group: {method : "POST", url:url+"group", isArray: false},
findGroup: {method : "GET", url:url+"findGroup", isArray: true}
});
}]);
I have this error:
angular.js:14328 Possibly unhandled rejection: {"data":"<!DOCTYPE html><html><head><title>Apache Tomcat/8.5.11 - Error report</title><style type=\"text/css\">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style> </head><body><h1>HTTP Status 400 - </h1><div class=\"line\"></div><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The request sent by the client was syntactically incorrect.</u></p><hr class=\"line\"><h3>Apache Tomcat/8.5.11</h3></body></html>","status":400,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"group","data":{"creatore":"ciro","gruppo":"nuovo","partecipanti":[{"id":0,"username":"a","email":"a#aa","password":null,"name":"a","surname":"a","longitude":0,"latitude":0,"checked":true},{"id":0,"username":"ciao","email":"ciao#ciao","password":null,"name":"ciao","surname":"ciao","longitude":0,"latitude":0,"checked":true}]},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json;charset=utf-8"}},"statusText":""}
This is my BE code. I have a spring controller that manage client requests
#RequestMapping(value = "/group", method = RequestMethod.POST)
public #ResponseBody
Group createGroup(#RequestBody Group json, HttpServletRequest request) throws SQLException, ClassNotFoundException {
Group g = DBUtils.insertGroup(json.getPartecipanti(), json.getGruppo(), json.getCreatore());
return g;
}
This is my DBUtils.insertGroup
public static Group insertGroup(List<String> members, String groupName, String userCreator) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn;
conn = DriverManager.getConnection(DB_URL, USER, PASS);
String sql = "insert into gruppo \n"
+ " (idCreatorUser,groupName,idPartecipante,data) values (?,?,?,?) ";
PreparedStatement pstm = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
java.util.Date date = new Date();
Timestamp timestamp = new Timestamp(date.getTime());
Utente creator = DBUtils.findUser(userCreator);
pstm.setInt(1, creator.getId());
pstm.setString(2, groupName);
pstm.setInt(3, creator.getId());
pstm.setTimestamp(4, timestamp);
int res = pstm.executeUpdate();
ResultSet rsId = pstm.getGeneratedKeys();
rsId.next();
int idGruppo = rsId.getInt(1);
Group response = new Group();
response.setIdGruppo(idGruppo);
response.setGruppo(groupName);
response.setIdCreatore(creator.getId());
response.setData(timestamp);
response.setPartecipanti(members);
response.setCreatore(creator.getUsername());
System.out.println(response);
sql = "insert ignore into gruppo \n"
+ " (idGruppo,idCreatorUser,groupName,idPartecipante,data) values (?,?,?,?,?) ";
pstm = conn.prepareStatement(sql);
Utente part;
for (int i = 0; i < members.size(); i++) {
pstm.setInt(1, idGruppo);
pstm.setInt(2, creator.getId());
pstm.setString(3, groupName);
part = DBUtils.findUser(members.get(i));
pstm.setInt(4, part.getId());
pstm.setTimestamp(5, timestamp);
pstm.executeUpdate();
}
conn.close();
return response;
}
I want to send in body some parameters but I can't to figure out what is the syntact error made.
I am very new to NodeJS, but I have been working to use it to serve my Angular project. I need to access an Oracle DB and return some information using a select statement. I have one statement that works correctly using a bind parameter that is set up like this:
var resultSet;
connection.execute("SELECT column_name, decode(data_type, 'TIMESTAMP(3)','NUMBER'"
+ ",'VARCHAR2','STRING','CHAR', 'STRING','NUMBER') as \"DATA_TYPE\""
+ "FROM someTable where table_name = :tableName",
[table], //defined above
{outFormat: oracledb.OBJECT},
function (err, result) {
if (err) {
console.error(err.message);
doRelease(connection);
return;
}
resultSet = result.rows;
console.log("Received " + resultSet.length + " rows.");
res.setHeader('Content-Type', 'application/json');
var JSONresult = JSON.stringify(resultSet);
// console.log(JSONresult);
res.send(JSONresult);
doRelease(connection);
});
This returns exactly what I want it to, with the bound variable being what I wanted it to be. Below is the code that doesn't work:
var resultSet;
connection.execute(
"SELECT DISTINCT :columnName from someTable",
['someColumn'],
{outFormat: oracledb.OBJECT},
function (err, result) {
if (err) {
console.error(err.message);
doRelease(connection);
return;
}
resultSet = result.rows;
console.log("Received " + resultSet.length + " rows.");
res.setHeader('Content-Type', 'application/json');
var JSONresult = JSON.stringify(resultSet);
console.log(JSONresult);
res.send(JSONresult);
doRelease(connection);
});
This returns {":COLUMNNAME": "someColumn"}. I do not understand why it won't display the results correctly. The two snippets of code are exactly the same, save the SQL query part. I know this a long question, but I really need help. Thank you!
You can bind data values, not the text of the statement itself.