node-postgres 创建数据库

Posted

技术标签:

【中文标题】node-postgres 创建数据库【英文标题】:node-postgres create database 【发布时间】:2014-01-15 18:44:53 【问题描述】:

我正在使用node-postgres,在我的应用程序开始时,我想检查数据库是否存在。所以我的工作流程思路如下:

    检查myDb是否存在 如果存在,则创建表 如果没有,则先创建数据库,然后创建表

正如您所见,这是一个非常简单的过程,但是,驱动程序实现需要有一个数据库名称postgres://username:password@host/database 才能连接,这意味着您需要先连接到数据库。

所以我现在正在做的是在开始时连接到postgres数据库,进行查询以创建数据库,如果它已经存在则捕获异常,然后关闭我的连接并连接到新创建的数据库,然后创建表。代码如下:

var conStringPri = 'postgres://' + username + ':' + password + '@' + host + 
    '/postgres';
var conStringPost = 'postgres://' + username + ':' + password + '@' + host + 
    '/' + dbName;

pg.connect(conStringPri, function(err, client, done)  // connect to postgres db
    if (err)
        console.log('Error while connecting: ' + err); 
    client.query('CREATE DATABASE ' + dbName, function(err)  // create user's db
        if (err) 
            console.log('ignoring the error'); // ignore if the db is there
        client.end(); // close the connection

        // create a new connection to the new db
        pg.connect(conStringPost, function(err, clientOrg, done) 
            // create the table
            clientOrg.query('CREATE TABLE IF NOT EXISTS ' + tableName + ' ' +
                    '(...some sql...)';
        );
    );
);

如您所见,我打开和关闭了两次连接,这种方式对我来说似乎是错误的。如果您提出更好的方法,我会很高兴,或者解释一下您是如何做到的。

【问题讨论】:

据我所知,没有命令可以切换您连接到的数据库(在 psql 中有 \c nameOfOtherDb 但这是 psql 中创建新连接并关闭旧连接的命令)。 另一种技术:您可以使用查询来查看它是否来自一个连接(来自“管理”连接):select count(*) from pg_catalog.pg_database where datname = 'the_db_name_here';,然后创建/打开第二个连接。如果您连接到 2 个数据库,这似乎不是问题。 获取可用的数据库并检查我的数据库是否存在将创建一个 if/else,这将破坏我的同步回调。这就是我最终创建数据库并捕获异常的原因 // ignore if the db is there 的行中,您忽略了所有错误。要忽略重复的数据库错误,您可以执行if (err && err.code === '42P04') console.log('ignoring the error'); else if (err) throw err; 之类的操作 【参考方案1】:

正如您所见,这是一个非常简单的过程,但是,驱动程序 实现需要有一个数据库名称 postgres://username:password@host/database 要连接,其中 意味着您需要先连接到数据库。

这不是因为驱动程序的实现,而是 PostgreSQL 本身。任何其他语言或驱动程序都一样。

客户端需要连接到数据库才能执行任何操作,包括CREATE DATABASE。除了postgres 数据库,template1 也经常用于此目的。

然后,由于您必须连接到新创建的数据库才能在其中创建对象,因此无法避免打开另一个连接。

简而言之,你正在做的事情无法简化,它已经是最优的了。

【讨论】:

【参考方案2】:

我刚刚为此编写了一个模块:https://github.com/olalonde/pgtools

var pgtools = require('pgtools');
pgtools.createdb(
  user: 'postgres',
  password: 'some pass',
  port: 5432,
  host: 'localhost'
, 'test-db', function (err, res) 
  if (err) 
    console.error(err);
    process.exit(-1);
  
  console.log(res);
);

希望它能让你的代码更简洁。

【讨论】:

【参考方案3】:

这有点老了,但我只是想分享一下我是如何处理这种设置的。

您需要从回调中调用第三个参数,即来自pg.connect(conn, (err, client, done) => )done。这将释放连接并恢复池。

 async.series([
   done => 
     pg.connect(connPrimary, (err, client, releaseConn) => 
      if (err) return done(err)

      client.query(`CREATE DATABASE $conf.database`, (err) => 
        if (err && !~err.message.indexOf('already exists')) 
          return done(err)
        

        client.end()
        releaseConn()
        done()
      )
    )
  ,
  done => 
    let connSecondary = `postgres://$conf.user:$conf.password@$conf.host:$conf.port/$conf.database`

    pg.connect(connSecondary, (err, client, releaseConn) => 
      if (err) return done(err)

      let createTableQuery = `CREATE TABLE IF NOT EXISTS test_table(_id bigint primary key, co2_field varchar(40) NOT NULL, temp_field int NOT NULL, quality_field decimal NOT NULL, reading_time_field timestamp NULL)`

      client.query(createTableQuery, err => 
        if (err) return done(err)

        releaseConn()
        done()
      )
    )    
  
], err => 
  should.ifError(err)
  doneInit()
)

【讨论】:

【参考方案4】:

安装

npm install --save -g pgtools

CLI 示例

createdbjs my_awesome_db --user=admin --password=admin

【讨论】:

【参考方案5】:

这是我使用的一个脚本,它基本上只是用 execa 执行 shell 命令:

import execa from 'execa';

class DatabaseService 
  public async setupDatabase() 
    const logCmd = (cmd: execa.ExecaChildProcess) => 
      cmd.stdout.on('data', (data) => 
        this.logger.log(data.toString());
      );

      cmd.stderr.on('data', (data) => 
        this.logger.error(data.toString());
      );
    ;

    const createUser = () => 
      return new Promise<void>((resolve, reject) => 
        const cmd = execa('createuser', [Config.databaseUser, '--superuser']);

        logCmd(cmd);

        let userExists = false;

        cmd.stderr.on('data', (data) => 
          if (
            data
              .toString()
              .includes(`role "$Config.databaseUser" already exists`)
          ) 
            userExists = true;
          
        );

        cmd.on('exit', (code) => 
          if (!userExists && code) 
            reject(new Error(`Failed to create user for database: $code`));
           else 
            resolve();
          
        );
      );
    ;

    const createDatabase = () => 
      return new Promise<void>((resolve, reject) => 
        const cmd = execa('createdb', [Config.databaseName]);

        logCmd(cmd);

        let databaseExists = false;

        cmd.stderr.on('data', (data) => 
          if (
            data
              .toString()
              .includes(`database "$Config.databaseName" already exists`)
          ) 
            databaseExists = true;
          
        );

        cmd.on('exit', (code) => 
          if (!databaseExists && code) 
            reject(new Error(`Failed to create database: $code`));
           else 
            resolve();
          
        );
      );
    ;

    await createUser();
    await createDatabase();
  

如您所见,脚本会检测用户或数据库是否已经存在,并将忽略这些事件中的错误,因为 Postgres 的预期状态已经满足,而这就是我运行它时所关心的全部。

【讨论】:

以上是关于node-postgres 创建数据库的主要内容,如果未能解决你的问题,请参考以下文章

pg(node-postgres)是不是自动清理数据

使用 node-postgres 更新数据的更简单方法?

为啥我不能使用 node-postgres 从数据库中删除?

PG(node-postgres)VS。续集

具有大量查询的 node-postgres

使用 node-postgres 在 postgres 中存储文件