Node-sqlite3: this.lastID not present after INSERT

Created on 31 Mar 2018  路  8Comments  路  Source: mapbox/node-sqlite3

When I have inserted data into a table, this.lastID does not exist, and thus I cannot get the id from the just run INSERT. I have seen the test for this functionality:
https://github.com/mapbox/node-sqlite3/blob/7322ea714b13451bab75d5232a1dd2a05fcb5052/test/affected.test.js#L19

That is a slightly different case than what I am trying to accomplish, so I'm wondering what I am missing, or if my approach is not supported.

Demo of my experience:

sudo apt-get install -y sqlite3 libsqlite3-dev

mkdir sqlitetest
cd sqlitetest

cat << EOF > package.json
{
  "name": "sqlitetest",
  "version": "0.1",
  "description": "SQLite test",
  "main": "demo.js",
  "private": true,
  "scripts": {
    "start": "node demo.js"
  }
}
EOF

yarn add sqlite3

cat << EOF > demo.js
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');

db.serialize(() => {
  db.run('CREATE TABLE IF NOT EXISTS t1 ( \
    id INTEGER PRIMARY KEY AUTOINCREMENT, \
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \
    a TEXT NOT NULL \
  )');

  let t1Id = null;
  db.run('INSERT INTO t1 (a) VALUES (?)', "aaa", err => {
    if (err) {
      console.error(err);
      process.exit(1);
    }
    console.log(this);
    console.log(this.lastID);
    console.log('lastID', this.lastID);
  });
});
EOF

node demo.js

the output looks like:

$ node demo.js 
{}
undefined
lastID undefined

Which is to say that after the INSERT has succeeded, this is the empty object {} and this.lastID is subsequently undefined.

I even created a second demo that is basically copy-pasted from the test case:

cat << EOF > demo.js
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');

db.serialize(() => {
  db.run("CREATE TABLE foo (id INT, txt TEXT)");
  var stmt = db.prepare("INSERT INTO foo VALUES(?, ?)");
  stmt.run(1, "demo", err => {
    if (err) throw err;
    console.log(this);
    console.log(this.lastID);
    console.log('lastID', this.lastID);
  });
});
EOF

But this gives the exact same output of the empty this, and thus undefined lastID.

Any help figuring this out? I'd love to get that last inserted id. Thanks.

Most helpful comment

Oh god, I just found out the problem, trying a guess... It is literally the ES6 arrow function syntax I chose. With just a slight change it works:

cat << EOF > demo.js
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');

db.serialize(() => {
  db.run("CREATE TABLE foo (id INT, txt TEXT)");
  var stmt = db.prepare("INSERT INTO foo VALUES(?, ?)");
  stmt.run(1, "demo", function (err) {  # FUNCTION INSTEAD OF ARROW LAMBDA
    if (err) throw err;
    console.log(this);
    console.log(this.lastID);
    console.log('lastID', this.lastID);
  });
});
EOF

Which gives me the expected output:

$ node demo.js 
Statement { sql: 'INSERT INTO foo VALUES(?, ?)', lastID: 1, changes: 1 }
1
lastID 1

I feel like this might merit a special callout somewhere, as ES6 code becomes increasingly popular. Perhaps in the wiki for this behavior?
https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param--callback

Docs do mention the absence of a this in arrow lambdas, but I did not realize it would have this kind of impact:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

All 8 comments

Oh god, I just found out the problem, trying a guess... It is literally the ES6 arrow function syntax I chose. With just a slight change it works:

cat << EOF > demo.js
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');

db.serialize(() => {
  db.run("CREATE TABLE foo (id INT, txt TEXT)");
  var stmt = db.prepare("INSERT INTO foo VALUES(?, ?)");
  stmt.run(1, "demo", function (err) {  # FUNCTION INSTEAD OF ARROW LAMBDA
    if (err) throw err;
    console.log(this);
    console.log(this.lastID);
    console.log('lastID', this.lastID);
  });
});
EOF

Which gives me the expected output:

$ node demo.js 
Statement { sql: 'INSERT INTO foo VALUES(?, ?)', lastID: 1, changes: 1 }
1
lastID 1

I feel like this might merit a special callout somewhere, as ES6 code becomes increasingly popular. Perhaps in the wiki for this behavior?
https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param--callback

Docs do mention the absence of a this in arrow lambdas, but I did not realize it would have this kind of impact:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

yep same issue here. after 30 mins of head scratching and rewriting came across your post and indeed made the same mistake of using arrow function instead of 'function(error)' >:-/
thanks for your post!

Is there not a better solution? I need to retain the scope of the outer context AND access lastID. I'd prefer to not do the whole var self = this; hack.

I also tried the solution here: https://stackoverflow.com/a/54423628/3042383, but it gives these errors:

TypeError: db.run(...) is not a function
in Database#get('select * from [table] where [condition]', {params... }, [Function])

this is your statement, use

stmt.run(xx, (err) => {
console.log(stmt.lastID);
});

Perfect! That's exactly what I needed, thank you @aikar !

im not sure this issue needs to remain open.

db.run() with fat arrow will be an issue because it uses a temporary statement that you don't have access to, but can be solved by preparing it yourself as shown above.

only other way i can see to improve that scenario is db.run(sql, params, (err, res, stmt) => {

});

if the run callback receives the statement as a third arg.

Yeah, I also ended up using the statement from db to
. var stmt = db.prepare("INSERT INTO foo VALUES(?, ?)"); stmt.run(1, "demo", err => { # FUNCTION INSTEAD OF ARROW LAMBDA if (err) throw err; console.log(stmt.lastID); });

This works fine.

Thank you so much. I didn't know about the db.prepare but after using the working part of your example I'm moving onto my next issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sushantdhiman picture sushantdhiman  路  20Comments

jpillora picture jpillora  路  18Comments

mdouglass picture mdouglass  路  17Comments

milu2003 picture milu2003  路  16Comments

sveinnM picture sveinnM  路  25Comments