Shoes.create = (newshoes, result) => {
sql.query("INSERT INTO shoes SET ? ", newshoes, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
console.log("created shoes: ", { id: res.insertId, ...newshoes });
result(null, { id: res.insertId, ...newshoes });
});
};
in that INSERT INTO shoes SET ? there is supposed to be two parameters (name and description). Doing this "INSERT INTO shoes SET ? ? ", newshoes, desc along with this line
console.log("created shoes: ", { id: res.insertId, ...newshoes });
result(null, { id: res.insertId, ...newshoes });
created an error.
I'm learning nodejs and sql query. What is the solution to the error?
In SQL you have to specify column names for insert and values in a different way.
So correct query would be:
INSERT INTO shoes(column1, column2) VALUES (value1, value2);
Look for examples in your database documentation, for PostgreSQL it would be:
https://www.postgresql.org/docs/current/sql-insert.html
Related
How can we get the list of all blogs group by tags from the userblogs table
sql query below:
select max(id) as id, max(blogdetails) as blog, tags, count (tags) as tagcount from userblogs group by tags;
I have tried so far;
app.get('/service/listofblogs', async (req, res) => {
try {
const blogData = await BlogModel.findAll(
{attributes: ['blogdetails', 'tags']},
{ group: ['tags'] }
);
res.status(200).json({ blogData });
} catch (e) {
res.status(500).json({ message: e.message });
}
});
Can you try with single value instead of array?
const blogData = await BlogModel.findAll(
{attributes: ['blogdetails', 'tags']},
{ group: 'tags' }
);
SELECT "count"(DISTINCT("displayedCandidates"))
from
(SELECT unnest("displayedCandidates") "displayedCandidates" FROM roles)
"displayedCandidates"
here the "displayedCandidates" column is of the type of string array which contains relevant candidateIds.What I want to query is the distinct count of displayed candidates.And this sql query is properly working.
Try this:
return model.findAll({
attributes: ['candidateId', 'displayedCandidates'],
where: {
candidateId: {
[Op.in]: sequelize.literal('(SELECT unnest("displayedCandidates") as
"displayedCandidates" FROM "Roles" WHERE "candidateId" ='+ '\'' + candidateId + '\')'
)
}
}
})
.then((model) => {
console.log(model);
})
.catch((err) => {
console.log(err);
});
Read the documentation, this might help you.
Sequelize Querying
I have implemented a REST API with express.js. I use it to connect to my database. The database has to tables. One is the table Person and the other is called Pet.
app.post('/persons', (req, res, next) => {
let firstname = req.body.firstname;
let lastname = req.body.lastname;
let petname = req.body.petname;
if (!firstname) {
return res.status(400).send({ error: true, message: 'Please provide first name' });
}else if (!lastname) {
return res.status(400).send({ error: true, message: 'Please provide last name' });
}else if (!petname) {
return res.status(400).send({ error: true, message: 'Please provide pet name' });
}
When i call this post method i want to check if a certain petname already exists in the database. If so, then get the petID and insert it with the first name and the last name in the table Person, so that a person is linked with a pet. If this petname does not exist, then create a new pet with this name and a new id in the table Pet. Then again save the id and the first name and last name to the table Person. So every petname should only exist once.
I know how to write the Person into the database:
Conn.query("INSERT INTO Person SET ? ", { FirstName: firstname, LastName: lastname, PetID: petid }, function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results, message: 'New person has been created successfully.' });
});
But now i still need the petID, if available, and if not create a new pet in the DB and return the id.
How do i do that?
I think checking before creating transaction is your option.
If pet exists you will get it's id, and if not - create new pet and also get the id.
I wrote a small sql script for psql:
WITH pet AS (
WITH new_row AS (
INSERT INTO Pets (id)
SELECT '{id}' WHERE NOT EXISTS (SELECT * FROM Pets WHERE id = '{id}')
RETURNING *
)
SELECT * FROM new_row
UNION
SELECT * FROM Pets WHERE id = '{id}' LIMIT 1
RETURNING *
)
INSERT INTO Person SET pet_id=pet.id;
SOURCE FROM RELATED QUESTION
Next step is creating transaction for person. Now you already have your pet id.
So i tried this but it does not work.
Conn.beginTransaction(function(error){
if (error) throw error;
Conn.query('Select PetID FROM Pet WHERE Petname = ' + mysql.escape(petname), function (error, results, fields){
if (error) {
connection.rollback(function() {
throw error;
});
}
else {
if (!results) {
Conn.query('INSERT INTO Pet SET ? ', { Petname: petname }, function (error, results, fields){
if (error) {
connection.rollback(function() {
throw err;
});
}
return res.send({ error: false, data: results, message: 'New pet has been created successfully.' });
});
}
let petid = results.insertId;
Conn.query('INSERT INTO Person SET ? ', { FirstName: firstname, LastName: lastname, PetID: petid}, function (error, results, fields){
if (error) {
connection.rollback(function() {
throw error;
});
}
Conn.commit;
return res.send({ error: false, data: results, message: 'New person has been created successfully.' });
});
}
});
});
What is wrong with this transaction?
I am trying to update my RDS Aurora database with simple information.
import * as AWS from 'aws-sdk';
import { BatchExecuteStatementRequest } from 'aws-sdk/clients/rdsdataservice';
const RDS = new AWS.RDSDataService();
export const create = async (event: any) => {
try {
const params: BatchExecuteStatementRequest = {
secretArn: 'arn:aws:secretsmanager:XXXXXXXXXXXXXXXXXXX',
resourceArn: 'arn:aws:rds:XXXXXXXXXXXXXXXXXXXXX',
schema: 'PUBLIC',
database: 'test_db',
parameterSets: [
[
{
name: 'FirstName',
value: {
stringValue: 'Joe',
}
},
{
name: 'LastName',
value: {
stringValue: 'Doe'
}
}
],
[
{
name: 'FirstName',
value: {
stringValue: 'Joyer',
}
},
{
name: 'LastName',
value: {
stringValue: 'Doyer'
}
}
]
],
sql: 'INSERT INTO test_table (FirstName, LastName) VALUES (:FirstName, :LastName)'
};
const res = await RDS.batchExecuteStatement(params).promise();
console.log({ result: res, params });
return {
statusCode: 200,
body: JSON.stringify(res)
};
} catch (err) {
console.error(err);
return {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: 'Could not create the note.'
};
}
};
This will generate an error:
{ BadRequestException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ’(’Joyer’, ‘Doyer’)' at line 1 }
The weird part is, it's working if I only add ONE person in parameterSets, so the error occur when I try to have more than one array.
I created my db in AWS console, this is the query for that:
CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;
CREATE TABLE IF NOT EXISTS test_table (
Id int NOT NULL AUTO_INCREMENT,
FirstName varchar(255),
LastName varchar(255),
PRIMARY KEY (Id)
);
I found the problem while I was writing the question, thought I will share it here anyway.
You can NOT have AUTO_INCREMENT!
This was the error, just remove it and everything works.
This was a couple of fun hours.....
I have a table user_address and it has some fields like
attributes: {
user_id: 'integer',
address: 'string' //etc.
}
currently I'm doing this to insert a new record, but if one exists for this user, update it:
UserAddress
.query(
'INSERT INTO user_address (user_id, address) VALUES (?, ?) ' +
'ON DUPLICATE KEY UPDATE address=VALUES(address);',
params,
function(err) {
//error handling logic if err exists
}
Is there any way to use the Waterline ORM instead of straight SQL queries to achieve the same thing? I don't want to do two queries because it's inefficient and hard to maintain.
The answer above is less than ideal. It also has the method as part of the attributes for the model, which is not correct behavior.
Here is what the ideal native solution looks like that returns a promise just like any other waterline model function would:
module.exports = {
attributes: {
user_id: 'integer',
address: 'string'
},
updateOrCreate: function (user_id, address) {
return UserAddress.findOne().where({user_id: user_id}).then(function (ua) {
if (ua) {
return UserAddress.update({user_id: user_id}, {address: address});
} else {
// UserAddress does not exist. Create.
return UserAddress.create({user_id: user_id, address: address});
}
});
}
}
Then you can just use it like:
UserAddress.updateOrCreate(id, address).then(function(ua) {
// ... success logic here
}).catch(function(e) {
// ... error handling here
});
Make a custom model method that does what you want using Waterline queries isntead of raw SQL. You will be doing two queries, but with Waterline syntax.
Example below (if you don't know about deferred objects then just use callback syntax, but the logic is the same):
var Q = require('q');
module.exports = {
attributes: {
user_id: 'integer',
address: 'string',
updateOrCreate: function (user_id, address) {
var deferred = Q.defer();
UserAddress.findOne().where({user_id: user_id}).then(function (ua) {
if (ua) {
// UserAddress exists. Update.
ua.address = address;
ua.save(function (err) {deferred.resolve();});
} else {
// UserAddress does not exist. Create.
UserAddress.create({user_id: user_id, address: address}).done(function (e, ua) {deferred.resolve();});
}
}).fail(function (err) {deferred.reject()});
return deferred.promise;
}
};
#Eugene's answer is good but it will always run 2 operations: findOne + update or create. I believe we can optimize it further because if the record exists we just need to run update. Example:
module.exports = {
attributes: {
user_id: 'integer',
address: 'string'
},
updateOrCreate: function (user_id, address) {
return UserAddress.update({user_id: user_id}, {address: address})
.then(function(ua){
if(ua.length === 0){
// No records updated, UserAddress does not exist. Create.
return UserAddress.create({user_id: user_id, address: address});
}
});
}
}
BTW, there is an open request to implement .updateOrCreate in waterline: #790