How to not insert two of the same values - sql

I'm using an input to allow user's to select files from their computer and add it to a list. I'm doing this by using a promise to load the files and creating an array of promises and adding that to my state
React JS
this.state = {
files: [],
};
const readFile = (file) => {
const fileReader = new FileReader();
return new Promise((resolve, reject) => {
fileReader.onerror = (error) => {
reject({ error })
}
fileReader.onload = (e) => {
resolve({
name: file.name.replace( /_|\.mp3/gi, " "),
link: e.target.result,
id: id++,
})
}
fileReader.readAsDataURL(file);
})
}
const allReaders = Array.from(event.target.files).map(readFile)
Promise.all(allReaders)
.then(fileList => {
console.log(this.state.files)
this.setState({ files: fileList });
})
.catch(error => {
console.error(error)
});
}
I'm then mapping through my files array to add those files to a list of text inputs. They're also able to reorder the list as well as change the text for each list item.
After that they will be able to save the list information to a database using a button.
React JS
save(event) {
event.preventDefault();
let files = this.state.files;
let data = files.map(( { name } , index) => ({ name, index : index }));
let request = new Request('http://localhost:3000/songs', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json' }),
body: JSON.stringify(data)
});
fetch(request)
.then((response) =>
response.json())
.then((data) => {
})
.catch((error) => {
console.log(error)
})
}
Node JS
*queries.js*
const addSong = (request, response) => {
const id = parseInt(request.params.id)
const { name, link, index } = request.body;
for (var i = 0; i < request.body.length; i++) {
pool.query('INSERT INTO songs (name, link, index) VALUES ($1, $2, $3) RETURNING *', [request.body[i].name, request.body[i].link, request.body[i].index], (error, results) => {
if (error) {
throw error
console.log(error)
} else {
console.log("Rows " + JSON.stringify(results.rows));
}
});
}
}
*index.js*
const app = express();
const db = require('./queries');
app.post('/songs', db.addSong)
It works but if I click save twice it saves the same data to the database. I guess what I want to be able to do is not save the object if it contains the same index as another object.

If you want to prevent duplicates on column index (which, by the way, is not a well-chosen column name since it is a reserved workd in almost all RDBMS), you can simply add a unique constraint on that column:
ALTER TABLE songs ADD CONSTRAINT song_unique_index UNIQUE ("index");
If an attempt is made to create a duplicate, the database will raise an error. In Postgres, you can even manage that error in your query, using handy clause ON CONFLICT.
For example, you can simply ignore duplicate errors on this specific column like this:
INSERT INTO songs (name, link, index)
VALUES ($1, $2, $3)
ON CONFLICT (song_unique_index) DO NOTHING
RETURNING *
Duplicates will not be inserted, and no error will be raised.

Related

SQL database not saving

I'm relatively new to SQLite and I've been trying to modify a project made by people over at glitch. The app is supposed to save text to a database, and my project link is this. Although the logs don't show any errors. I can't get any data to save no matter what I do. (I changed the database file saving location from .data/sqlite.db to /data.sqlite.db). I assume this is some small issue I'm just new about, but I can't find anything about it on the internet.
app.use(express.static("public"));
// init sqlite db
const dbFile = "./data/sqlite.db";
const exists = fs.existsSync(dbFile);
const sqlite3 = require("sqlite3").verbose();
const db = new sqlite3.Database(dbFile);
// if ./.data/sqlite.db does not exist, create it, otherwise print records to console
db.serialize(() => {
if (!exists) {
db.run(
"CREATE TABLE Dreams (id INTEGER PRIMARY KEY AUTOINCREMENT, dream TEXT)"
);
console.log("New table Dreams created!");
// insert default dreams
db.serialize(() => {
db.run(
'INSERT INTO Dreams (dream) VALUES ("test"), ("hi sam"), ("fortnite gaming chair 3d")'
);
});
} else {
console.log('Database "Dreams" ready to go!');
db.each("SELECT * from Dreams", (err, row) => {
if (row) {
console.log(`record: ${row.dream}`);
}
});
}
});
// http://expressjs.com/en/starter/basic-routing.html
app.get("/", (request, response) => {
response.sendFile(`${__dirname}/views/index.html`);
});
// endpoint to get all the dreams in the database
app.get("/getDreams", (request, response) => {
db.all("SELECT * from Dreams", (err, rows) => {
response.send(JSON.stringify(rows));
});
});
// endpoint to add a dream to the database
app.post("/addDream", (request, response) => {
console.log(`add to dreams ${request.body.dream}`);
// DISALLOW_WRITE is an ENV variable that gets reset for new projects
// so they can write to the database
if (!process.env.DISALLOW_WRITE) {
const cleansedDream = request.body.dream;
db.run(`INSERT INTO Dreams (dream) VALUES (?)`, cleansedDream, error => {
if (error) {
response.send({ message: "error!" });
} else {
response.send({ message: cleansedDream+"success" });
}
});
}
});
// endpoint to clear dreams from the database
app.get("/clearDreams", (request, response) => {
// DISALLOW_WRITE is an ENV variable that gets reset for new projects so you can write to the database
if (!process.env.DISALLOW_WRITE) {
db.each(
"SELECT * from Dreams",
(err, row) => {
console.log("row", row);
db.run(`DELETE FROM Dreams WHERE ID=?`, row.id, error => {
if (row) {
console.log(`deleted row ${row.id}`);
}
});
},
err => {
if (err) {
response.send({ message: "error!" });
} else {
response.send({ message: "success" });
}
}
);
}
});
// listen for requests :)
var listener = app.listen(process.env.PORT, () => {
console.log(`Your app is listening on port ${listener.address().port}`);
});

How to store third-party API array data into elephantSQL database using React.js front-end and node.js back-end?

Coding newbie here. So I've been trying to build a dictionary app using wordsapi and was trying to find a way to store the dictionary api into my back end. Below is my code on the front end using React.
const _addToQuollection = async (e) => {
e.preventDefault();
const apiUrl = 'http://127.0.0.1:3333/quollection/add';
const submitResponse = await fetch(apiUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ word: word, definition: definition }),
})
.then((response) => response)
.catch((e) => {
console.log(e);
});
console.log("word added to quollection: ", submitResponse)
if (submitResponse.status === 200) {
console.log("submit response is success")
}
}
In my console, the req body information for word and definition array pops up as so... console.log picture showing req body for string word and array definition
But the post request is only inserting into word and not definition... QUERY: INSERT INTO quollection (word) VALUES ('quote'
My backend route using Node.js looks like this...
router.post('/add', async(req, res) => {
console.log('backend reqBody: ', req.body);
const { word, definition } = req.body;
const response = await quollectionModel.addToQuollection(word, definition);
if (response.rowCount >= 1) {
console.log('def added success!')
res.sendStatus(200)
} else {
res.sendStatus(500)
}
});
And the backend model looks like this...
static async addToQuollection(word, definition) {
try {
const response = await db.result(`INSERT INTO quollection (word, definition) VALUES ($1, $2);`, [word, definition]);
return response;
} catch (error) {
console.log('error', error.message)
return error.message
}
}
This was how I created my schema...
CREATE TABLE quollection (
id serial PRIMARY KEY,
word text,
definition text[1000000]
);
And this is the result in postico...
postico screenshot with successful word column and null definition column
Ahhh I hope this was a decent enough explanation. Any help would be much appreciated T_T Thank you!

mongoose save by reference multiple document

I'd like to make new document by reference of two documents.
**app.post('/student_badge/register', async (req, res) => {
const name = req.body.name;
const category = req.body.category;
People.find({name: name}, '_id', function (err, doc) {
if (err) return handleError(err);
var obj = eval(doc);
id = obj[0]._id;
})
Badge.find({category: category}, 'points title', function (err, doc) {
if (err) return handleError(err);
var obj2 = eval(doc);
points = obj2[0].points;
title = obj2[0].title;
console.log(title + " " + points);
});
data = {
id: id,
title: title,
points: points
}
console.log("data: " + data);
const sbadge = new StudentBadge(data);
sbadge.
save()
.then(result => {
res.status(201).json({
message: 'Post created successfully!',
post: result
});
})
.catch(err => {
console.log(err);
});
});**
But I cannot call three variables like id, title, points to store them in 'data'.
How can I call variables?
Thanks
Your code does not work because the variables you are trying to access, i.e. id, title, points, are being set on a callback function that gets executed asynchronously.
I would suggest using async/await instead of callbacks so that you can thereafter use the data from the other documents you are querying in the same function. In addition, I suggest to use findOne() since you only access the first entry in db.
Something like the example below should work: (I have abstracted the middleware in a separate function for clarity to use with express)
const createStudentBadge = async (req, res, next) => {
const {name, category} = req.body;
let person, badge;
try {
person = await Person.findOne({name}); // shortcut for {name: name}
badge = await Badge.findOne({category});
} catch(err) {
// handle error
}
if (!person || !badge) {
// Handle case where no document has been found in db
// This case will not throw an error when calling find()
}
data = {
id: person._id,
title: badge.title,
points: badge.points
}
const studentBadge = new StudentBadge(data);
try {
await studentBadge.save();
} catch(err) {
// handle error
}
res.status(201).json({
message: 'Post created successfully!',
post: studentBadge
});
}
app.post('/student_badge/register', createStudentBadge);
If you wanted to perform the querying in parallel, you could make use of Promise.all() and run both queries at the same time. More info can be found at MDN documentation

(VUEJS) Access methods from Axios inside created

I have just a simple error which is confusing me almost 3 weeks.
my question is about, I want to return string from methods "idvideo" at the end of my axios API url, but nothing is happen.
as you can see on my code below.
I have been searching for solution and try an error for many times, but still never found any best answer that can help me out.
export default {
data() {
return {
errors: [],
videos: [],
items: []
}
},
methods: {
idvideo: function() {
const data = this.items
const result = data.map((item) => {
return {
fetchId: item.snippet.resourceId.videoId
};
}).sort((a, b) => b.count - a.count);
var i, len, text;
for (i = 0, len = result.length, text = ""; i < len; i++) {
text += result[i].fetchId + ",";
}
var x = text.slice(0, -1);
return(x);
}
// Fetches posts when the component is created.
created() {
// Ini adalah API utk playlist yang dipilih
axios.get("https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=PLjj56jET6ecfmosJyFhZSNRJTSCC90hMp&key={YOUR_API_KEY}")
.then(response => {
// JSON responses are automatically parsed.
this.items = response.data.items
})
.catch(e => {
this.errors.push(e)
}),
// Ini adalah API utk data yang dipilih
axios.get('https://www.googleapis.com/youtube/v3/videos?part=snippet%2CcontentDetails%2Cstatistics&key={YOUR_API_KEY}&id='+this.idvideo())
.then(response => {
// JSON responses are automatically parsed.
this.videos = response.data.items
})
.catch(e => {
this.errors.push(e)
})
},
}
I really appreciate any kind of solutions that can help me out. If you guys have best way to implement this function, let me know.
Sorry for my bad english and any mistakes. This is my very second time post question in this platform.
Thank you very much sir!
Since, they are asynchronous requests, I have following solution in my mind.
Solution:
Move the next axios call within the first axios call. This is because, only after first call, the 'items' will be retrieved and then it will assigned to this.items So next axios call will have the required data from idvideo() function.
export default {
data() {
return {
errors: [],
videos: [],
items: []
}
},
methods: {
idvideo: function() {
const data = this.items
const result = data.map((item) => {
return {
fetchId: item.snippet.resourceId.videoId
};
}).sort((a, b) => b.count - a.count);
var i, len, text;
for (i = 0, len = result.length, text = ""; i < len; i++) {
text += result[i].fetchId + ",";
}
var x = text.slice(0, -1);
return(x);
}
// Fetches posts when the component is created.
created() {
// Ini adalah API utk playlist yang dipilih
axios.get("https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=PLjj56jET6ecfmosJyFhZSNRJTSCC90hMp&key={YOUR_API_KEY}")
.then(response => {
// JSON responses are automatically parsed.
this.items = response.data.items
// Ini adalah API utk data yang dipilih
axios.get('https://www.googleapis.com/youtube/v3/videos?part=snippet%2CcontentDetails%2Cstatistics&key={YOUR_API_KEY}&id='+this.idvideo())
.then(response => {
// JSON responses are automatically parsed.
this.videos = response.data.items
})
.catch(e => {
this.errors.push(e)
})
}
})
.catch(e => {
this.errors.push(e)
}),
,
}

Send single response after multiple updates

I have an array of items that I am passing to an API endpoint (using Sequelize as my ORM). I'm trying to iterate over each item and update it, however I'm getting a Unhandled rejection Error: Can't set headers after they are sent.
stepsController.put = (req, res) => {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
steps.map(step => {
Step.findOne({ where: { id: step.id } })
.then(savedStep =>
savedStep
.update({
order: step.order,
})
.then(success => res.status(200).send(success))
.catch(error => res.send(error))
)
.then(ok => res.status(200).send(ok))
.catch(err => res.send(err));
});
};
I believe this is because it's sending the response for each item. Sequelize's update method is a promise. How can I iterate over all of the items and make sure all of the items are updated before sending a single successful response?
There are three ways you can do
Promise.all
Co
Async Await
1) Here it is , you can use Promise.all :
stepsController.put = (req, res) => {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
Promise.all(steps.map(step => {
return Step.findOne({ where: { id: step.id } }).then(savedStep =>
return savedStep.update({
order: step.order,
})
.catch(error => error)
).catch(err => err)
}))
.then(ok => res.status(200).send(ok))
.catch(err => res.send(err));
};
2) Another way is to use co :
const co = require('co');
stepsController.put = co.wrap(function* (req, res) => {
try {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
for(let i=0;i<steps.length ; i++) {
let savedStep = yield Step.findOne({ where: { id: steps[i].id } });
if(savedStep)
yield savedStep.update({ order: steps[i].order});
}
res.status(200).send();
}
catch(err){
res.send(err);
}
});
3) If you’re using Node 8.0+ , there is no need of any package you can directly use async await :
stepsController.put = async(req, res) => {
try {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
for(let i=0;i<steps.length ; i++) {
let savedStep = await Step.findOne({ where: { id: steps[i].id } });
if(savedStep)
await savedStep.update({ order: steps[i].order});
}
res.status(200).send();
}
catch(err){
res.send(err);
}
};