-
-
Notifications
You must be signed in to change notification settings - Fork 411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Help me use SQLite! #125
Comments
Is it possible to insert multiple rows from an array of objects? Say I have this: var data = [
{ foo: 1, bar: 2 },
{ foo: 3, bar: 4 }
]; I'd like to be able to do this: db.prepare('INSERT INTO baz VALUES ($foo, $bar)').run(data); Not sure if running INSERT statements in a loop is efficient. As a side note, sqlite does does support insertion of multiple values. |
Using a loop is quite efficient, @dimitry-ishenko. There are two things to be aware of:
Here's an example of what (I believe) you're trying to do: const insert = db.prepare('INSERT INTO baz VALUES ($foo, $bar)');
const insertMany = db.transaction((data) => {
for (const obj of data) insert.run(obj);
});
insertMany([
{ foo: 1, bar: 2 },
{ foo: 3, bar: 4 }
]); |
Hi, I am curious about the performance of the method you just mentioned @JoshuaWise. How does this compare to actually running a batch write? The tradeoff being the const insertMany = data => {
const valuesStr = Array(data.length).fill('(?, ?)').join(',')
const sql = `INSERT INTO baz VALUES ${valuesStr}`
const flattened = data.reduce((acc, d) => {
acc.push(Object.values(d))
return acc
}, [])
db.run(sql, flattened)
} when comparing the two executing directly like so |
@andykais, there's nothing stopping you from re-using prepared statements in the |
One of the biggest performance penalties of using an async API is the inability to re-use prepared statements |
Hi, can i just use the prepare statement + run statement for creating tables or creating trigger? const statement = db.prepare('CREATE TABLE IF NOT EXISTS ? (?)');
{some foo}
statement.run(tableName, tableColumns); or am i doing something wrong? |
@Nikumarekko the only thing wrong with your code is that SQLite3 does not allow you to bind strings for identifier names (such as table or column names). You can only use bound values for actual run-time values. // No bound parameters for table/column names
const createTable = db.prepare(`CREATE TABLE IF NOT EXISTS ${tableName} (${tableColumns})`);
createTable.run();
// Use bound parameters for actual strings
const select = db.prepare(`SELECT * FROM ${tableName} WHERE foo = ?`);
const results = select.all('someString'); Keep in mind that because you have to use string interpolation for table and column names, they should only come from trusted sources. |
Thanks for your quick reply, helps me a lot |
hi @JoshuaWise I'm trying to use this module with Express.js but for some reason when I call code is pretty simple
any suggestion how to find the cause of the problem? thanks |
@bombard-kb |
@JoshuaWise it looks like I was trying to use "on conflict statement" with sqlite3 version, which doesn't support it |
How do I use better-sqlite3 with a precompile version of SQLite? |
@JefStat |
Hi Can I store an image as a I am developing an electron/desktop app where I am storing a lot of images. Before I have used the browsers internal indexeddb where the images were stored as a Blob. I then created an As indexeddb is limited in some ways, I came across |
Can I have table name as a query parameter? For example, in |
I have a general query. Is there any overhead in having many SQLite databases open at the same time? I'm trying to understand if we should have a single DB or several smaller DBs (e.g 100s individual dbs). We are currently having a single database and prefixing the tables with |
A small, probably unimportant amount. SQLite needs several hundred K of ram.
You almost certainly should have a single database. This is not related to needs of the tool. You can treat the single database like it's distinct; the converse is not true. One will eventually need to be retooled; the other will not.
Use a single table with a defining column instead.
You absolutely can. You just shouldn't. You will lose out on the ability to make any decisions across the set. |
@danielepolencic The correct way of handling this would be to have a single database that has a table that contains your customers with the primary key of say, customer_id. Then all your other tables have a foreign key matching up to that customer_id so that a given customer’s data can be selected from the table. This allows a single table for each set of data instead of juggling what sounds like a nightmare scenario of tables all with different names that represent the same data sets for different customers. |
Hi, I made it so I can check easier if a row with that userId already exist or not. But how would I check for the count since |
@Dezaku I would change it to this: function userExists(userId) {
const statement = db.prepare(`SELECT 1 FROM main WHERE userId = ?`);
const row = statement.get(user.id);
return row !== undefined
}
const doTheyExist = userExists(user.id) |
Thats a way easier way, thank you! |
That was the long version that makes it clear what's happening. You could shorten it to this: function userExists(userId) {
return db.prepare('SELECT 1 FROM main WHERE userId = ?').get(userId) !== undefined
}
const doTheyExist = userExists(user.id) |
Alright, thank you! |
repeatedly preparing the query is wasteful const exists_q = db.prepare('select 1 from main where userid = ?'),
userExists = userId => exists_q.get(userId) !== undefined; |
Is there a way to wait for a database entry to appear? events.on('someEvent', event => {
db.prepare('INSERT INTO events (id, someValue) VALUES (?, ?)')
.run(event.id, event.someValue);
});
events.on('otherEvent', event => {
const previousEvent = db.prepare('SELECT * FROM events WHERE id = ?')
.get(event.referenceId);
}); Now say that there's some code in |
I'm uploading images to my node.js server and saving those in a table in my sqlite db. I'd like to stream that file upload straight to the table rather than reading the whole image in memory before doing the insert. I saw that SQLite should support this via What I have is a data type of imageDb
.prepare(
/* sql */ `
INSERT INTO "Images"
(updatedAt, contentType, blob)
VALUES (@updatedAt, @contentType, @blob)
`,
)
.run({updatedAt: new Date().toISOString(), contentType, blob: data}) // <-- data is the Uint8Array in an AsyncIterable Tips are appreciated. Thanks! |
I am using verbose function but it logs queries even when there is an error like Unique constraint violation, in my use case I want to read queries if it's executed successfully. It would be a great help if you have any suggestion. |
Hello, I am inserting some values into a table:
How I can retrieve the inserted id? |
@pc-magas - sqlite3 .run returns an object with two properties. one is the count of changed rows; the other is the last insert id. const stmt = db.prepare('INSERT INTO cats (name, age) VALUES (?, ?)');
const info = stmt.run('Joey', 2);
console.log(info.changes); // => 1
console.log(info.lastInsertId); // => if first cat, 1; otherwise higher |
SELECT
COUNT(progress_id) total_done,
SUM(session_length)
FROM
progress_table
WHERE
strftime("%Y-%m-%d",time_stamp,"localtime") > (SELECT DATE("now", "-7 day","localtime")) What I am doing wrong here, In "DB Browser for SQLITE", this query does not throw any error, How ever in better-sqlite, node is throwing
Is there a different way of writing this query for better-sqlite to work?. |
Use single quotes for strings and you'll be fine. SQL strings are generally single quoted, double quotes generally used for quoting identifiers e.g. if you have a column name with unsafe chars like a space in them. I've noticed that SQLite is inconsistently forgiving in this regard (there's presumably a pattern to it, but I haven't looked - I just use single quotes by habit anyway, but a colleague ran into this in a subtle and confusing bug). |
Thank you so much for your quick reply, it worked. |
Idiomatic connection approach with a web-server (e.g. Express)?Most other DBs rely on connection pools that handle reconnects for us (allowing concurrent reads as well).
Then the question arises: how to handle DB disconnects? According to the docs But, if I connect once, without a connection pool, the connection will eventually be lost and the app will crash. Surprisingly, I couldn't find more information about reconnects and proper connection management within a web server setup. So asking it here 🤔 Seems like an important topic to reflect in the docs though. |
@ivan-kleshnin , sqlite is not a server client model. it's a flat file parser local library. there aren't many realistic situations under which it would "disconnect." |
I'm looking to use db.aggregate() to loop through data in my table but I can't seem to figure out how to pass 2 fields to the Here's an example of one of those functions which currently only provides a value but not a key to the predicate function: filter2(predicate) {
this.#db.aggregate('filter', {
start: [],
step: (accumulator, currentValue) => {
const parsed = JSON.parse(currentValue);
if (predicate(parsed)) {
accumulator.push(parsed);
}
return accumulator;
},
result: (accumulator) => JSON.stringify(accumulator),
});
const results = this.#db
.prepare(`SELECT filter(value) FROM mytable`)
.pluck()
.get();
return JSON.parse(results);
} Is there any solution to this with the use of aggregate? |
@JoshuaWise If you could help with the above that would be awesome. This is a bit out of the depths of mostly everyone I know that uses sqlite ;) What I feel I'm looking for would look like : filter2(predicate) {
this.#db.aggregate('filter', {
start: [],
step: (accumulator, [value, key]) => {
const parsed = JSON.parse(value);
if (predicate(parsed, key)) {
accumulator.push(parsed);
}
return accumulator;
},
result: (accumulator) => JSON.stringify(accumulator),
});
const results = this.#db
.prepare(`SELECT filter(value, key) FROM mytable`)
.pluck()
.get();
return JSON.parse(results);
} this gives me an error about the wrong number of arguments. Arrays and objects don't work either. I Really hope there's a way :( |
@eslachance, You almost got it, just get rid of the array brackets: db.aggregate('filter', {
start: [],
step: (accumulator, value, key) => {
const parsed = JSON.parse(value);
if (predicate(parsed, key)) {
accumulator.push(parsed);
}
return accumulator;
},
result: (accumulator) => JSON.stringify(accumulator),
});
const results = db
.prepare(`SELECT filter(value, key) FROM mytable`)
.pluck()
.get();
return JSON.parse(results); |
@JoshuaWise This is awesome! I guess it really was a question of matching parameter counts between the functions. Might I suggest this as an example in the docs somewhere? I even went and looked at your tests which all look at a single row, so I was wondering about the possibility, even. But now I know, and Enmap will be better for it, so thank you! |
* move dev dependencies out from dependencies block of package json * use single quote for strings in triggers - WiseLibs/better-sqlite3#125 (comment) * remove not null constraint from date column of account and chart tables
How can I find where SQLite stores data when using an in-memory database (:memory:)? The memory consumption of a Node.js server process using an SQLite in-memory database decreased from 1.5 GB to 50 MB in Task Manager, while the SQLite database still contains 1 GB of data. The database size was found using this query: SELECT (page_count - freelist_count) * page_size AS size FROM pragma_page_count(), pragma_freelist_count(), pragma_page_size(). |
General Help Thread
This thread is for anyone who needs help using SQLite or Node.js with regards to
better-sqlite3
.It's common for issues to appear with titles like
"Help me do ABC"
or"How do I build an app like XYZ?"
. These types of issues aren't real issues withbetter-sqlite3
, so they will be closed and considered a duplicated of this thread. Therefore, post your questions here instead. If you're lucky, friendly members of the community may chime in here to help you.The text was updated successfully, but these errors were encountered: