I am trying to insert multiple values into the nosql database cassandra, using an array, but when I use the code below, instead of adding a row for each of the values stored in foo5 it only ends up adding two rows. The two rows added contain the same value in col5 and col3
var insert2 = "INSERT INTO content (col, col2, col3, col4, col5) VALUES (?, ?, ?, ?, ?);"
for(var i = 0; i < foo5.length; i++) {
client.execute(insert2, [foo, foo2, foo3, foo4, foo5[i]], {prepare : true}, function(err, result) {
if(err) throw err;
});
}
for example this is what the result looks like(col is the primary key):
col | col2 | col3 | col4 | col5
---------+---------+-----------+--------+--------
8909265 | text | 8759 | 5332 | 7480
1769288 | text | 8759 | 5332 | 7480
I want to add a row for every single value in the array foo5. This is the expected result. How can I achieve this:
col | col2 | col3 | col4 | col5
---------+---------+-----------+--------+--------
8909265 | text | 8759 | 5332 | 1234
1769288 | text | 8759 | 5332 | 5678
3254786 | text | 8759 | 5332 | 9101112
4357234 | text | 8759 | 5332 | 1314151617
assuming foo5 = {1234, 5678, 9101112, 1314151617};
UPDATE:
after adding a recursive function as suggested by someRandomSerbianGuy this is what my code looks like:
function recursion(i, counter) {
var insert2 = "INSERT INTO content (col, col2, col3, col4, col5) VALUES (?, ?, ?, ?, ?);"
if(counter == i) {
return;
} else {
client.execute(insert2, [foo, foo2, foo3, foo4, foo5[i]], {prepare : true}, function(err, result) {
if(err) throw err;
recursion(++i, counter);
});
}
}
recursion(0, foo5.length);
I am still getting the same results.
Switch to a promisified client module and use an async function. You will need to research promises and async functions in Node. It will take a bit of time getting used to it, but is necessary because this type of problem happens all the time with callbacks.
Code will be simpler, and it will work in a more straightforward way, with one insert at a time:
async function insert(sql, data) {
for (let i=0; i<data.length; i++)
await client.insert(sql, data[i]);
}
This is because Node.js is asynchronous. You can use Promises for this, or recursive function instead for loop.
By using recursive function instead for loop you are enabling it to finish client.execute and than triggering it again with different data. By using for loop you are just calling client.execute bunch of times with same data.
Example (for recursion in Node.js, be aware that there are better ways to write this, but I wanted to make it simple so you would understand syntax):
function recursion(i, howManyTimes){ //First you define function
if(i === howManyTimes){ //If it's called enough times just escape recursion
return;
}else{
//Your code for DB should be here, after successful .execute call call line under this one!
recursion(++i, howManyTimes);
}
}
recursion(0, 5); //You can call your function now since you defined it
Related
I know the title might not be self explanatory so I will try to present my problematic with as much clarity as possible.
I have a NodeJS app that needs to regularly post some of its content to an external API. This content is stored in a MySQL database, and is scattered between several tables. So let's say we have two tables (with a lot more rows than this obviously but you catch my drift) :
Table A:
+-------+---------+---------+---------+
| id | field_1 | field_2 | field_3 |
+-------+---------+---------+---------+
| uuid1 | value1 | value2 | value3 |
+-------+---------+---------+---------+
Table B:
+-------+-------------------+---------+---------+
| id | id_field_A (FK) | field_4 | field_5 |
+-------+-------------------+---------+---------+
| uuid3 | uuid1 | value4 | value5 |
+-------+-------------------+---------+---------+
and for each row of table A joined with table B I have to Post an object which DTO would look like this :
{
"title": "value3",
"attributes: {
"10": "value1",
"9": "value2",
"1": "value4",
"16": "value5"
}
}
So each id ("1", "9", "10", "16" in the example) is used as a key in the object attributes and its value should match the value of one of our field from the tables A or B.
The external API ids ("1", "9", "10", "16") should not vary between the different environments so my idea was to create a new table to map these ids to table and field names and get this data from our database any time we need to post or update the data to the API. Like this:
Table api_attribute:
+-------+-----------------+------------+-----------------+
| id | table_name | field_name | id_external_api |
+-------+-----------------+------------+-----------------+
| uuid4 | Table A | field_1 | "10" |
+-------+-----------------+------------+-----------------+
| uuid5 | Table A | field_2 | "9" |
+-------+-----------------+------------+-----------------+
| uuid6 | Table B | field_4 | "1" |
+-------+-----------------+------------+-----------------+
| uuid7 | Table B | field_5 | "16" |
+-------+-----------------+------------+-----------------+
I'm pretty new to the development game so I'm not sure if this would be a recommended solution, and if it is not I'm simply struggling to find any articles on this kind of subject so I guess I'm missing some keywords here for this particuliar problem...
Edit: Now that I've written all of that I realize it might be a bit overkill and I just need to map all these fields in plain javascript since the id can't be determined programmatically anyway. Maybe I should be using a simple class to create the DTO and use it in my api service like so :
>>>>>>>>>> apiDTO.class.js
class ApiDTO {
constructor({field_1: value1, field_2: value2, ..., field_5: value5}) {
this.title: value3;
this.attributes = {
"10": value1,
"9": value2,
"1": value4,
"16": value5
};
}
}
module.exports = ApiDTO ;
>>>>>>>> api.service.js
const ApiDTO = require('./apiDTO.class');
module.exports.createAnApiEntity = async () => {
const allDataToSendToApi = await dataFromDService.getAllFromTableAJoinTableB();
for (dataToSend of allDataToSendToApi) {
const apiDto = new ApiDto(dataToSend);
sendToApi(apiDto);
}
}
The thing is, this solution would mean that only developers would be able to change the ids since it is hardcoded data and the changes would require a new release if we were to add fields and values to the payload...
Assuming dataToSend is always a flat object, you can put the DTO definition in your second snippet to a file (e.g. dtoTemplate.json) in the exact JSON format you currently have. That file can be read by your code during the runtime (you can use this answer or maybe one of the async methods discussed in the linked question) and you can dynamically match the values in your template JSON file with the keys in dataToSend.
A simple implementation can be:
function convertToApiDTO(dataToSend) {
const fs = require('fs');
const templateJson = fs.readFileSync('path/to/dtoTemplate.json', 'utf8');
return JSON.parse(
templateJson,
(dtoKey, dbKeyOrValue) => dbKeyOrValue in dataToSend ?
dataToSend[dbKeyOrValue] :
dbKeyOrValue
);
}
I suggest adding extra error handling since having invalid JSON in your file can break this function. Also if your JSON file can be edited by untrusted third parties parsing it can also be dangerous due to prototype poisoning vulnerability.
Note that if dbKeyOrValue is not a key in dataToSend, this function sets the dbKeyOrValueas a constant value with key dtoKey in the result object. If you'd rather skip these fields then you can return undefined instead of dbKeyOrValue.
I have two tables in mysql and I'm trying to make a query call. In the Item table, the tid is a foreign key, but in the query call, I want to get all the information in the Items table, but instead of getting the tid, I want to get the name of the Types the tid refers to. What is the proper query call here?
|_______Items______| |________Types______|
| id {PK} | | tid {PK} |
| name | | name |
| description | | description |
| tid {fk} | | |
app.get('/getData', function(req, res) {
var content = {};
mysql.pool.query('SELECT * FROM Items WHERE id=?', [req.query.id],
function(err, rows, fields) {
if (err) {
next(err);
return;
}
content.results = JSON.stringify(rows);
res.send(content.results);
});
});
I believe the correct query should be:
mysql.pool.query('SELECT * FROM Items INNER JOIN Types on Types.tid = Items.tid WHERE Items.id=?', [req.query.id],
This will return all the fields from both tables, but only show the row from Types where the tid is used in the row of Items which has the id passed in req.query.id
This is done using a SQL INNER JOIN - if you're not familiar with this way of joining tables, it's quite fundamental to SQL and you should study it.
P.S. If you want just a specific selection of columns from the two tables (as hinted at in the question), you can write it like this, for instance:
mysql.pool.query('SELECT Items.id, Items.name, Items.description, Types.name FROM Items INNER JOIN Types on Types.tid = Items.tid WHERE Items.id=?', [req.query.id],
I am currently designing a Discord bot. I am working on a module to easily make commands.
This is currently my commands module.
module.exports = {
add: function(name, help, permissions, callback) {
var command = {};
command['name'] = name;
command['help'] = help;
command['permissions'] = permissions;
command['callback'] = callback;
list.push(command);
},
parse: function(message, data) {
var args = message.split(' ');
for (var i = 0; i < list.length; i++) {
var command = list[i];
if (command.name == args[0]) {
isAuthorized(command.permissions, data, function() {
console.log("RAN");
command.callback(data, args);
});
}
}
},
get: function() {
return list;
}
}
and here is how I would go about using it.
commands.add('ping', 'Send a ping-pong request.', null, function(data, args) {
if (args[1] == "-p") {
discord.sendMessage({to: data.channelID, message: "pong"});
} else {
discord.sendMessage({to: data.channelID, message: "ding"});
}
});
It all good, however I am worry about the design. I am not liking it too much as it can be buggy and annoying. For instance, the above would simply parse a command by a whitespace. Like so:
!ping -d
It will call the ping function and check the first element of args to see if it contain a "-d" flag. I want this to be as similar to Linux terminal as I can get. The above is simple, but what about a command that takes more than one flag? For example:
!ping -d -help
Which will obviously print out "ding" and if implemented it should also print something that would describe the command and it arguments.
But what if I write something like
!ping -help -d -f -m
How would that work out? I rather not have a bunch of conditional statement.
Permissions
Another concern I thought about is permission levels. I have each role setup in a database.
+----+-----------+
| id | name |
+----+-----------+
| 1 | guest |
| 2 | member |
| 3 | mod |
| 4 | developer |
| 5 | admin |
| 6 | master |
| 8 | owner |
+----+-----------+
These roles were created using this command.
roles.createRole = function(name) {
database.insert('roles', ['name'], ['"' + name + '"']);
}
commands.add('createrole', 'Create a new role.', ['master'], function(data, args) {
var role = args[1];
if (role) {
roles.createRole(role);
}
});
And if they have the permission called "master" they are able to create a role.
This is how I am storing the users information.
-------------------+
| id | username | discord_id | permissions
|
+----+---------------+--------------------+-------------------------------------------------------+
| 1 | kurieita | 000000000 | {"test":true,"master":true,"admin":true,"guest":true} |
Obviously I have the role and can execute the command. But what if I set someone to "admin", I also want them to have moderator powers. I would have to give them moderator powers too.
Ideas
Here are my ideas I came up with (while I was writing this)
Add "value" field for database.roles and check if user permission level is greater than the required permission field.
I thought about doing a more OOP approach. Something along these lines.
var command = new Command(name, description);
command.setCallback(function() {});
command.setFlag(name, function() {});
I hadn't really thought much about that or how it would work tho.
Another idea I had which is similar to the way I am doing it now is this
commands.add(name, description, permissions, function(data, args, flags) {}
where name and description are string, permission is a index array. Data is an array based wit Discord information (userID, channelID, etc), args is an array with values. For example: !message text "text" would be an arg and flags would contain anything prepended with "-". For instance !ping -d, "d" would be in the flags array.
Questions
How would I go about implementing a Linux like parser for my discord bot commands module?
What would the best way to deal with permission levels be?
Any help is appreciated.
Thank you in advanced.
I'm a new Cordova-Android program maker. I've successfully create and insert the local database fields. But I stuck when I want to display them into input tag.
This is my table :
+----+------+---------+
| id | word | stats |
+----+------+---------+
| 1 | abc | stackov |
| 2 | def | erflow |
+----+------+---------+
I try this code
$(document).ready(function(){
docDB = window.openDatabase("Test", "1.0", "Test Data", 50000);
docDB.transaction(function (tx) {
tx.executeSql("SELECT * FROM Test WHERE word='abc'", [], function (tx, results) {
var dblen = results.rows.length;
if( dblen>0 ){
document.getElementById("abc").value = results.rows.item(0)['stats'];
}
}, null);
});
});
I've searching for simplest way, because I just want to display single SQL column value word='abc' and other word value such word='def'. Can someone correct it?
And I would insert the result value into a input field
Name : <input type="text" id="abc">
Thanks for answering :)
Try adding your search value outside of the SQL statement and refer to the item as an object, see below:
$(document).ready(function(){
docDB = window.openDatabase("Test", "1.0", "Test Data", 50000);
docDB.transaction(function (tx) {
tx.executeSql("SELECT * FROM Test WHERE word=?", ['abc'], function (tx, results) {
var dblen = results.rows.length;
if( dblen>0 ){
document.getElementById("abc").value = results.rows.item(0).stats;
}
}, null);
});
});
Removing the search parameters from the actual SQL statement has a few different benefits. One is, by passing in the variables they are escaped correctly as to not break the statement. Another is, it makes the statement more clear when debugging code.
For those who may not be familiar with the syntax, you add ? where you would place variable input or a search parameter and then in the array after the statement [] items are removed from the array and added to the SQL statement.
Example:
..."SELECT * FROM thisTable WHERE id IN(?) AND name LIKE ? and gender=?", ['1,32,456', '%tim%', 'M']
Generates:
"SELECT * FROM thisTable WHERE id IN('1,32,456') AND name LIKE '%tim%' and gender='M'"
You need to reaffirm the assessment in your sql code
I use Node.js and i want to INSERT few value in my table.
like:
id | profile_id | user_id
1 | 2 | 7
2 | 2 | 3
3 | 2 | 4
4 | 2 | 6
i have an array (user_id) with all my date(ids), i have to do a foreach in my array for insert each user_id value like
foreach...
connection.query('INSERT INTO mytable SET ?', my_obj, function(error,risultato) { ...
or i can do a cycle inside mysql with one statement?
You can use the following syntax for multiple insterts in MySQL:
INSERT INTO mytable (id, profile_id, user_id) VALUES(?,?,?),(?,?,?),(?,?,?);
Therefore yor code would be:
connection.query("INSERT INTO mytable (id, profile_id, user_id) VALUES(?,?,?),(?,?,?),(?,?,?)",
[id1, profile_id1, user_id1, id2, profile_id2, user_id2, id3, profile_id3, user_id3],
function(err, result){ .... });
After answer #Mustafa i do it: (use sugar.js and felixge/node-mysql)
var place ="(";
rows.each(function(n) {
columns.add(n.profile_id);
columns.add(n.user_id);
columns.add(new Date());
place += '(?,?,?),';
});
place= place.slice(0,place.lastIndexOf(","));
var sql = 'INSERT INTO mytable (profile_id,user_id,created) VALUES '+place+' ON DUPLICATE KEY UPDATE id=id';
connection.query(sql,
columns
, function(error, rows) {
if (error) {
var err = "Error on " + error;
console.dir(err);
console.log('>>>>>ERROR<<<<< ' + err);
throw err;
}
connection.release();
callback(rows);
I hope to help someone