In my DB I have about 50 tables. Every table has created_at and updated_at. Of course, I could create 50 migrations, but there would be similar. Is there any opportunity to create knex script which could be make 50 migrations to entire DB?
Here is example of code:
exports.up = function(knex, Promise) {
return knex.schema.alterTable("balance", table => {
table.timestamp("created_at").defaultTo(knex.fn.now()).alter()
table
.timestamp("updated_at")
.defaultTo(knex.raw("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")).alter()
})
};
exports.down = function(knex, Promise) {
return knex.schema.alterTable("balance", table => {
table.dateTime("created_at").defaultTo(null).alter()
table.dateTime("updated_at").defaultTo(null).alter()
})
};
Balance is the name of table, so I have to create ~50 migrations changing only DB's name. Is it possible to make everything easier using just 1 knex script?
Thanks for answers!
Just like that:
const showList = await knex.raw(
`SELECT table_name FROM information_schema.tables WHERE table_schema = 'your_db';`)
for (const item of showList[0]) {
await knex.schema.alterTable(`${item.table_name}`, table => {
table.timestamp("created_at").defaultTo(knex.fn.now()).alter()
table
.timestamp("updated_at")
.defaultTo(knex.raw("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")).alter()
})
}
Related
I am trying to get most recent transaction by using this query inside my NestJs application
public findUsersWithRecentTransactions(): Promise<UserEntity[]> {
return this.createQueryBuilder('users')
.innerJoinAndSelect('users.transactions', 'transactions')
.where(
'(users.userType = :userTypeParent AND users.registrationStatus = :registrationStatusParent)',
{
userTypeParent: UserType.Parent,
registrationStatusParent: RegistrationStatus.onboarded,
},
)
.orderBy('transactions.created_at', 'DESC').getMany();
}
This returns an array of transactions sorted by their created_at date in descending order. However, I am trying to get the most recent transaction using the query itself so that I don't have to loop over the entities to get the transaction.
const usersWithTransactions = await this.userRepository.findAllUsersWithTransactions();
for (const user of usersWithTransactions) {
const mostRecentTransaction = user?.transactions[0];
Hi you should try limit method.
public findUsersWithRecentTransactions(): Promise<UserEntity[]> {
return this.createQueryBuilder('users')
.innerJoinAndSelect('users.transactions', 'transactions')
.where(
'(users.userType = :userTypeParent AND users.registrationStatus = :registrationStatusParent)',
{
userTypeParent: UserType.Parent,
registrationStatusParent: RegistrationStatus.onboarded,
},
)
.orderBy('transactions.created_at', 'DESC')
.limit(1) // I include this.
.getMany();
}
Check this code above. I added '.limit(1)'.
I am trying to run a simple script on a simple PostgreSQL database with one table. When I use db.query('SELECT * FROM groups')
I get the error ERROR: relation "groups" does not exist at character 15
I ran the SQL in a Postgresql sandbox and it worked fine when I selected *, so I don't know what the problem here is. Here is the SQL Code
DROP TABLE IF EXISTS groups;
CREATE TABLE groups (
id serial PRIMARY KEY,
name varchar(255) NOT NULL,
birthPlace varchar(255) NOT NULL; );
INSERT INTO groups (name, birthPlace) VALUES
( 'Marco', 'Italy' ),
( 'Callum', 'Scotland' ),
( 'Bob, Ireland' );
And this is the javascript code where I use db.query
const db = require ('../dbConfig')
class Groups {
constructor(data){
this.id = data.id
this.name = data.name
this.birthPlace = data.birthPlace
}
static get all() {
return new Promise (async (resolve, reject) => {
try {
const groupData = await db.query('SELECT * FROM groups;')
const groups = groupData.rows.map(d => new Groups(d))
resolve(groups);
} catch (err) {
reject("Error retrieving groups")
}
})
}
}
module.exports = Groups;
I have read that this error can arise when quotes or capitals were used when the table is created but I haven't used either anywhere in my code. I hope these code snippets suffice, any help would be greatly appreciated.
I have 2 tables, producers and contacts. To add information into the contacts table I must first add information to the producers table. This is my unit test:
'use strict'
const Contacts = require('../modules/contacts.js')
const Producers = require('../modules/producers.js')
describe ('Add contact information()' , () => {
test('Add contacts', async done => {
expect.assertions(6)
const producer = await new Producers()
await producer.addProducer('James')
const contact = await new Contacts()
await contact.addContacts('James', 'www.johnwick.com', 'john#johnwick.com', '07724890765', '24, John Wick Street, London')
const data = await contact.getAll()
await expect (data.length).toBe(1)
expect (data[0].ProducerID).toBe(1)
expect (data[0].ProducerWebsite).toBe('www.johnwick.com')
expect (data[0].ProducerEmail).toBe('john#johnwick.com')
expect (data[0].ProducerNumber).toBe('07724890765')
expect (data[0].ProducerAddress).toBe('24, John Wick Street, London')
done()
})
})
The problem is that when the producers table gets created when using the addProducer function it does not persist for the addContacts function to use it. How do I solve that? Here's the feedback from the Jest Unit Test:
FAIL unit tests/contacts.spec.js
Add contact information()
× Add contacts (80ms)
● Add contact information() › Add contacts
SQLITE_ERROR: no such table: producers
console.log modules/producers.js:22
Add Producer James
console.log modules/producers.js:32
Producer successfuly added.
console.log modules/producers.js:67
[ { ProducerID: 1, ProducerName: 'James' } ]
As you can see, it does create it, but only after the error is thrown??
Here's the code for the producers table being made:
'use strict'
const sqlite = require('sqlite-async')
module.exports = class Producers {
//Create Database Table if it doesn't exist
constructor(dbName = ':memory:') {
return (async() => {
this.db = await sqlite.open(dbName)
const sql = 'CREATE TABLE IF NOT EXISTS producers(ProducerID INTEGER PRIMARY KEY UNIQUE, ProducerName TEXT NOT NULL UNIQUE)'
await this.db.run(sql)
return this
})()
}
//Add function to add producers to database if not existing or add product types if producer exists.
async addProducer(name) {
console.log('Add Producer', name)
//Check if there are any Producers with the same name
let sql = `SELECT * FROM producers WHERE ProducerName="${name}"`
const data = await this.db.all(sql)
//If producer doesn't exist add to database
if(data.length === 0) {
sql = `INSERT INTO producers (ProducerName) VALUES("${name}")`
await this.db.run(sql)
console.log('Producer successfuly added.')
}
//Else return error saying producer exists
else {
console.log('Producer already exists.')
throw new Error ('Producer already exists.')
}
}
And here's the code for the contacts table being made:
'use strict'
const sqlite = require('sqlite-async')
module.exports = class Contacts {
//Create Database Table if it doesn't exist
constructor(dbName = ':memory:') {
return (async() => {
this.db = await sqlite.open(dbName)
const sql = 'CREATE TABLE IF NOT EXISTS contacts(ProducerID INTEGER, ProducerWebsite TEXT, ProducerEmail TEXT, ProducerNumber INTEGER, ProducerAddress TEXT)'
await this.db.run(sql)
return this
})()
}
async addContacts (ProducerName, ProducerWebsite, ProducerEmail, ProducerNumber, ProducerAddress){
// if(isNaN(Number.parseInt(ProducerNumber))) throw new Error('The Producer Number cannot contain letters')
let sql = `INSERT INTO contacts (ProducerID, ProducerWebsite, ProducerEmail, ProducerNumber, ProducerAddress) VALUES (
(SELECT ProducerID FROM producers WHERE ProducerName="${ProducerName}"),
"${ProducerWebsite}", "${ProducerEmail}", "${ProducerNumber}", "${ProducerAddress}")`
await this.db.run(sql)
}
I think each class is creating it's own in-memory database independent from the other.
According to https://www.sqlite.org/inmemorydb.html
Every :memory: database is distinct from every other. So, opening two
database connections each with the filename ":memory:" will create two
independent in-memory databases.
So either create the DB at a single place and reuse the instance or use one of the methods in the link to share the in-memory database between the entities.
I am studying SQLite for Node.js. Currently I am at the very beginning.
I tried to insert row to a table but got error. The code I am using comes from this tutorial.
This is the code:
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('./database/sq-lite-data-base.db', (err) => {
if(err) {
return console.log(err.message);
}
console.log("Connected to database!")
});
// Create table named 'users' with two columns: 1 - 'name' which values to be of type "text",
// and "age" of type "integer"
// db.run('CREATE TABLE users(name text, age integer)'); //When this line is not connected I get different error: "The table users already exists"
// Insert two rows to table "users"
db.run('INSERT INTO users(name, age) VALUES("Riko", 29)', ['C'], (err) => {
if(err) {
return console.log(err.message);
}
console.log('Row was added to the table: ${this.lastID}');
})
The error I get is:
SQLITE_ERROR: no such table: users
Another thing that puzzles me is the second parameter of the function db.run. In my case I have passed the argument ['C']. But what does this argument do, or what is it designated for?
First you have to check the user table in your db '/database/sq-lite-data-base.db'.
If not:
db.run('CREATE TABLE users(name TEXT,age INT)');
And you have to change the code in above snippet like this
db.run('INSERT INTO users(name, age) VALUES(?, ?)', ['Raiko',29], (err) => {
if(err) {
return console.log(err.message);
}
console.log('Row was added to the table: ${this.lastID}');
})
You can also refer about sqlite tutorial.http://www.sqlitetutorial.net/sqlite-nodejs/insert/
Try creating the table users first, before inserting any data in it (this probably caused the error):
db.run('CREATE TABLE users(name)');
Then insert the data into the table by putting a questionmark as placeholder in VALUES. The second argument of db.run is then used to pass the actual name value to sqllite.
db.run('INSERT INTO users(name) VALUES(?)', ['Riko'])
You can also use a database browser to gain more insight as to why your having problems: http://sqlitebrowser.org/.
If you have to insert data for multiple columns with large data. see the query if you want good Ui for handling db.
use sqlitestudio for userface based Sqlite db view: SqliteStudio
firstly check db and table is exist or not.then insert multiple values :
var data=[
['Mungade','26'],
['Nagnath','27']
]
for (var i=0;i<data.length; i++){
db.run("INSERT INTO user(name,age) values(?,?)",data[i][0],data[i][1],(err,rows)=>{
if(err){
throw err;
}
console.log('Insert Success');
})
}
its working for me.
A possible answer might be that your DB is referenced incorrectly. If this is the case it will create an empty DB named 'databasesq-lite-data-base.db' and since this DB is empty it will not find the table.
So a connection will work but it will not be the DB you wanted it to be.
In your windows explorer look whether and empty DB with the above name was created somewhere.
you need to serialize it all.
It is not possible to do 2 things at the same time except if you serialize
db.serialize(() => {
db.run('CREATE TABLE users(name text, age integer)');
// Insert two rows to table "users"
db.run('INSERT INTO users(name, age) VALUES("Riko", 29)', ['C'], (err) => {
if (err) {
return console.log(err.message);
}
console.log('Row was added to the table: ${this.lastID}');
})
}
I am using Knex.JS migration tools. However, when creating a table, I'd like to have a column named updated_at that is automatically updated when a record is updated in the database.
For example, here is a table:
knex.schema.createTable('table_name', function(table) {
table.increments();
table.string('name');
table.timestamp("created_at").defaultTo(knex.fn.now());
table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("deleted_at");
})
The created_at and updated_at column defaults to the time the record is created, which is fine. But, when that record is updated, I'd like the updated_at column to show the new time that it was updated at automatically.
I'd prefer not to write in raw postgres.
Thanks!
With Postgres, you'll need a trigger. Here's a method I've used successfully.
Add a function
If you have multiple migration files in a set order, you might need to artificially change the datestamp in the filename to get this to run first (or just add it to your first migration file). If you can't roll back, you might need to do this step manually via psql. However, for new projects:
const ON_UPDATE_TIMESTAMP_FUNCTION = `
CREATE OR REPLACE FUNCTION on_update_timestamp()
RETURNS trigger AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
`
const DROP_ON_UPDATE_TIMESTAMP_FUNCTION = `DROP FUNCTION on_update_timestamp`
exports.up = knex => knex.raw(ON_UPDATE_TIMESTAMP_FUNCTION)
exports.down = knex => knex.raw(DROP_ON_UPDATE_TIMESTAMP_FUNCTION)
Now the function should be available to all subsequent migrations.
Define a knex.raw trigger helper
I find it more expressive not to repeat large chunks of SQL in migration files if I can avoid it. I've used knexfile.js here but if you don't like to complicate that, you could define it wherever.
module.exports = {
development: {
// ...
},
production: {
// ...
},
onUpdateTrigger: table => `
CREATE TRIGGER ${table}_updated_at
BEFORE UPDATE ON ${table}
FOR EACH ROW
EXECUTE PROCEDURE on_update_timestamp();
`
}
Use the helper
Finally, we can fairly conveniently define auto-updating triggers:
const { onUpdateTrigger } = require('../knexfile')
exports.up = knex =>
knex.schema.createTable('posts', t => {
t.increments()
t.string('title')
t.string('body')
t.timestamps(true, true)
})
.then(() => knex.raw(onUpdateTrigger('posts')))
exports.down = knex => knex.schema.dropTable('posts')
Note that dropping the table is enough to get rid of the trigger: we don't need an explicit DROP TRIGGER.
This all might seem like a lot of work, but it's pretty "set-and-forget" once you've done it and handy if you want to avoid using an ORM.
You can create a knex migration using timestamps:
exports.up = (knex, Promise) => {
return Promise.all([
knex.schema.createTable('table_name', (table) => {
table.increments();
table.string('name');
table.timestamps(false, true);
table.timestamp('deleted_at').defaultTo(knex.fn.now());
})
]);
};
exports.down = (knex, Promise) => {
return Promise.all([
knex.schema.dropTableIfExists('table_name')
]);
};
With timestamps a database schema will be created which adds a created_at and updated_at column, each containing an initial timestamp.
To keep the updated_at column current, you'll need knex.raw:
table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
To skip the knex.raw solution, I suggest using a high level ORM like Objection.js. With Objection.js you could implement your own BaseModel which then updates the updated_at column:
Something.js
const BaseModel = require('./BaseModel');
class Something extends BaseModel {
constructor() {
super();
}
static get tableName() {
return 'table_name';
}
}
module.exports = Something;
BaseModel
const knexfile = require('../../knexfile');
const knex = require('knex')(knexfile.development);
const Model = require('objection').Model;
class BaseModel extends Model {
$beforeUpdate() {
this.updated_at = knex.fn.now();
}
}
module.exports = BaseModel;
Source: http://vincit.github.io/objection.js/#timestamps
This is my way of doing that in Mysql 5.6+
The reason I didn't use table.timestamps is because I use DATETIME instead of timestamp.
table.dateTime('created_on')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP'))
table.dateTime('updated_on')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
This is not a feature of Knex. Knex only creates the columns, but does not keep them up to date for you.
If you use, the Bookshelf ORM, however, you can specify that a table has timestamps, and it will set & update the columns as expected:
Bookshelf docs
Github issue
exports.up = (knex) => {
return knex.raw(create or replace function table_name_update() RETURNS trigger AS $$ begin new.updated_at = now(); RETURN NEW; end; $$ language 'plpgsql'; create or replace trigger tg_table_name_update on table_name before update for each row execute table_name_update();)
};
exports.down = (knex) => {
return knex.raw(drop table if exists table_name; drop function if exists table_name_update;)
};
You can directly use this function
table.timestamps()
This will create the 'created_at' and 'updated_at' columns by default and update them accordingly
https://knexjs.org/#Schema-timestamps