How can I write a function that will delete just one row (ideally the last one) that has a given name (which may not be unique).
I have tried using row count, limits, and my own built in function (below). None of these have worked.
app.delete('/FamilyMember/:db', (req, res) => {
let db = openDB("ClientsDatabases/"+req.params.db);
let ids = [];
db.serialize(()=>{
db.each('select * from family', (err, row)=> {
if (row.name == req.body.name) {
ids.push(row.id);
}
})
db.run("DELETE FROM family WHERE id = ?",ids[ids.length-1], (err)=> {
console.log("Here is the err "+err);
if (!err) console.log('Succesful # deleting', req.body.name);
});
})
res.send();
}, () => {
db.close();
})
My expected output is for only one row with the given name to be deleted, but the table doesn't change and no errors are caught.
Any particular reason you've got single quotes (') around your ? parameter in your call to Statement#run? Nothing in the API documentation suggests that this is correct practice, could be an explanation as to why your query is mangled to the point where it doesn't delete anything, but also doesn't throw an error. I'd expect your call to .run() to look something more like the below:
db.run("DELETE FROM family WHERE id = ?",ids[ids.length-1], (err)=> {
console.log("Here is the err "+err);
if (!err) console.log('Succesful # deleting', req.body.name);
});
You may alternatively be interested in simplifying your queries into a single statement that will grab the maximum id (provided the id is incremented each time) and delete that record:
db.run("DELETE FROM family WHERE id = MAX(id)", (err)=> {
console.log("Here is the err "+err);
if (!err) console.log('Succesful # deleting', req.body.name);
});
This eliminates the need to load all the contents of family first just to grab a single id from it.
Related
I get data from a HTML form, I would like to save this data into two dependent tables.
At the moment I came up with the following node.js code:
...
db.serialize(function() {
var lastID;
db.run('INSERT INTO Idea(title,description) VALUES(?1,?2)', {
1: formData.nameText,
2: formData.ideaText
}, function(err){
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted into Idea with rowid ${this.lastID}`);
lastID = this.lastID;
console.log(`last inner ID ` + lastID);
});
db.run('INSERT INTO Places(lon,lat,IdeaID) VALUES(?1,?2,?3)', {
1: formData.lon,
2: formData.lat,
3: lastID
}, function(err){
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted with rowid ${this.lastID}`);
console.log(`IdeaID in db ` + lastID);
});
db.close();
})
The console output looks good, the database data however isn't.
The console shows:
A row has been inserted into Idea with rowid 75
last inner ID 75
A row has been inserted with rowid 16
IdeaID in db 75
Inside the database the lastID stays null.
Am I missing something? Is this the wrong way to go about it?
I solved this issue (with a phone call to my brother). Here is my solution:
db.serialize(function () {
var lastID;
db.run('INSERT INTO Idea(title,description) VALUES(?1,?2)', {
1: formData.nameText,
2: formData.ideaText
}, function (err) {
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted into Idea with rowid ${this.lastID}`);
db.run('INSERT INTO Places(lon,lat,IdeaID) VALUES(?1,?2,?3)', {
1: formData.lon,
2: formData.lat,
3: this.lastID
}, function (err) {
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted with rowid ${this.lastID}`);
});
db.close();
});
})
This works because the callback (last part of the first db.run call) is executed after the first part.
One important bit is to move the db.close(); inside the callback, otherwise the connection to the database will be closed before the part inside the callback is executed.
I am working with a NodeJS application which fetches film names and description from an Sqlite-3 file when user send a GET to /films. There seems to be a thing which I am missing while pushing the object to an array. I don't get what I am missing. The object does not get pushed to the array and always shows empty [] when I res.json() it back as response.
app.get('/films', (req, res) => {
let db = new sqlite3.Database('./data.db', sqlite3.OPEN_READWRITE, err => {
if (err) return console.error(err.message)
console.log('DB connected')
})
var films = []
db.serialize(() => {
db.each('select * from film', (err, row) => {
if (err) return console.log(err.message)
// console.log(row.name + '\t' + row.description)
films.push({
"name": row.name,
"description": row.description
})
})
})
res.json(films)
db.close(err => {
if (err) return console.error(err.message)
console.log('DB coonnection closed')
})
})
Your issue is that Express returns response object before the database retrieves any values. To fix this you’d normally move it inside the callback function.
In your case though db.each() method actually accepts 2 functions. The 1st one is callback which runs after each value is retrieved and wouldn’t be any help at all. The 2nd one is called complete in documentation and does exactly what you need.
Here’s the full reference in docs for db.each() from node-sqlite3 wiki.
With that you could write your code this way:
db.each(
'select * from film',
(err, row) => { /* Does normal stuff */ }),
(err, num) => { /* Sends response to client */
res.json(films);
console.log(`Retrieved ${num} films`); // (Just to show what the 2nd argument does)
}
);
Keep in mind that if your film database is not particularly huge docs actually recommend to use db.all method instead.
I'm using node v14.2 and sqlite3: https://github.com/mapbox/node-sqlite3
I'm trying to determine if a table exists, and if it does, make a query against it. I've tried:
data = []
db.run("SELECT name FROM sqlite_master WHERE type='table' AND name='mytable';", result => {
console.log(result)
if (result) {
db.each("SELECT * FROM mytable;", (err, row) => {
data.push(row)
})
}
})
console.log(data)
However, my array data never gets pushed to, even when the table mytable exists. I've also tried testing for table existence with PRAGMA table_info('mytable');. How could I add to data once I confirm that mytable exists?
The issue I see in your code is, the console.log is outside of the callback function.
data = []
db.all("SELECT name FROM sqlite_master WHERE type='table' AND name='mytable';", function(err, rows) {
rows.forEach(function (row) {
data.push(row)
});
console.log(data)
});
What you need to understand in JS is, the callbacks are async and might get called after the next line gets executed. In your case, most likely the console.log got executed before the call back finished.
Update: Just realised the run function does not return anything.
I figured out the problem. db.run()'s second argument, result, is null if the query was successful and error if it was not. Thus, I should error if result, rather than the opposite. Here's the working code:
data = []
db.run("SELECT name FROM sqlite_master WHERE type='table' AND name='mytable';", result => {
if (result) {
console.error(result)
} else {
db.each("SELECT * FROM mytable;", (err, row) => {
data.push(row)
})
}
console.log(data)
})
I know that on robomongo if I want to find _id of user where username = test2 I can use
db.getCollection('user').find({},{_id:1},{"username":"test2"})
now, on visual studio code, I want to find value of field "disabled" from user collection where field "username" value equal to variable "tempusername" value. I tried:
colUser = mongoDb.collection("user");
var status = colUser.find({},
{ disabled:1},{ username:tempusername},function (err, doc) {
console.log(doc);
});
but it shows value of status is "undefined". What is the write code for this?
I think it's something you're looking for.
const url = 'mongodb://localhost:27017'
MongoClient.connect(url, (err, db) => {
const dbo = db.db('mydb')
dbo.collection('user').find({disabled:'1',username:tempusername}).toArray((err, doc) => {
if(err){
console.log(err)
}
console.log(doc)
db.close()
})
})
I found the answer, basically the way it work is the result will be return inside the function, so I have to put it like this:
var statusbuffer;
colUser.findOne({ username:tempusername},{ _id:0,disabled:1},function (err, userstatus){
// User result only available inside of this function!
if (err) {
next("Failed to update records");
} else {
console.log("disabled status here:",userstatus.disabled) // => yields your user results
statusbuffer = userstatus.disabled;
next();
}
});
thanks all for your comments!
I am making a single API call to a route (MEAN stack) to populate a chart.js graph on the front end. The API call needs to return year-to-date, month-to-date, and historical data (year-to-date last year, month-to-date last year, etc.). The functional programming best practices I'm trying to follow are making this a mess; is there a better way?
Here is the template I am filling in so far:
router.post('/sales_chart', (req, res, next)=>{
const store = req.body.store;
const date = req.body.date;
dailySalesModel.getSalesYTD (store, date, (err, daily_data)=>{
if(err) logger.error(err);
if(!daily_data) {
return res.json({success: false, message: 'No daily sales data found'});
}
let sales = [];
// **calculate sales year-to-date**
// Fetch the same data from one year earlier.
dailySalesModel.getSales (store, SAME_DAY_LAST_YEAR, (err, last_year_daily_data)=>{
if(err) throw err;
if(!last_year_daily_data) {
return res.json({success: false, message: 'No last year daily sales data found'});
}
let last_year_sales = [];
// **calculate sales year-to-date**
dailySalesModel.getSalesMTD (store, date, (err, mtd_data) => {
if(err) logger.error(err);
if(!mtd_data) {
return res.json({success: false, message: 'No MTD sales data found'});
}
let mtd_sales = [];
// **calculate sales month-to-date**
// Fetch the same data from one year earlier.
dailySalesModel.getSalesMTD(store, SAME_DAY_LAST_YEAR, (err, last_year_mtd_data) => {
if(err) logger.error(err);
if(!last_year_mtd_data) {
return res.json({success: false, message: 'No last year MTD sales data found'});
}
let last_year_mtd_sales = [];
// **calculate sales month-to-date**
// and so on...
dailySalesModel.getEvenMoreHistoricalData(...)
...
})
});
return res.json({success: true, sales_data: { sales: sales,
last_year_sales: last_year_sales,
mtd_sales: mtd_sales,
last_year_mtd_sales, mtd_last_year_sales,
date: date } });
});
})
});
...and I'm starting to feel like all the 'nested' functions are not necessary and there must be a better way to do this. For example, I don't think this handles cases where some function calls return null or empty data (maybe a new store wasn't open last year on the specified date) but I want to keep fetching the rest of the data for return.
Is there a better way to make several calls and return all the calculated data as a single JSON object?
Can you write your dailySalesModel methods as promises? That would save you from callback hell a little bit.
Another thing you can do is separate each of these into middlwares. A middleware in express is just a function that runs in between when the request is made and the response is sent. So, for example, you might have a middlewares.js file:
function getSalesYTD(req, res, next) {
const { store, date } = req.body
dailySalesModel.getSalesYTD(store, date, (err, result) => {
if (err) return next(err)
res.locals.daily_data = result
next()
})
}
function getSales(req, res, next) {
// etc
// access daily_data on res.locals.daily_data
}
(If you haven't run into res.locals before, it's just a property on the response object that's there for you to store stuff in during one request/response cycle. It's there for the duration of the cycle and is cleared out for each new request.)
And then in your route, just chain them all along:
const { getSalesYTD, getSales, otherThings } = require('./middlewares')
router.post('/sales_chart', getSalesYTD, getSales, otherThings, (req, res) => {
res.json({
daily_data: res.locals.daily_data
// etc
})
})
Is this the type of thing you're hoping to accomplish?
The other benefit of doing it like this is that if you need to make one of those requests in a different route, you don't have to write it out again -- you can just use the same middleware, provided you remember where on res.locals you put the data.
Here's an example of a route that uses this pattern.