用node-postgres更新数据更简单吗?

qeeaahzv  于 2023-01-12  发布在  Node.js
关注(0)|答案(5)|浏览(131)

我使用的是一流的插件节点postgres,https://github.com/brianc/node-postgres
我有这个更新调用。我有一个大约30列在我的在我的表。有没有更简单的方法来更新这些然后这样做?

/*
 Post /api/project/products/:pr_id HTTP/1.1
 */
exports.updateProduct = function(req, res){
  pg.connect(cs, function(err, client, done) {
    var query = "UPDATE products SET pr_title = ($1), pr_usercode = ($2) WHERE pr_id=($3)";
    client.query(query, [req.body.pr_title, req.body.pr_usercode, req.params.pr_id], function(err, result) {
      if (handleErr(err, done)) return;
      done();
      sendResponse(res, result.rows[0]);
    })
  });
};

我这里只有三列。当我写所有30列时,它会很混乱,很难维护。一定要用一个简单的行更新req.body中的所有列吗?
有什么想法吗?

new9mtju

new9mtju1#

你可以像这样展开一个函数:

function updateProductByID (id, cols) {
  // Setup static beginning of query
  var query = ['UPDATE products'];
  query.push('SET');

  // Create another array storing each set command
  // and assigning a number value for parameterized query
  var set = [];
  Object.keys(cols).forEach(function (key, i) {
    set.push(key + ' = ($' + (i + 1) + ')'); 
  });
  query.push(set.join(', '));

  // Add the WHERE statement to look up by id
  query.push('WHERE pr_id = ' + id );

  // Return a complete query string
  return query.join(' ');
}

然后这样使用它:

/*
 Post /api/project/products/:pr_id HTTP/1.1
 */
exports.updateProduct = function(req, res){
  pg.connect(cs, function(err, client, done) {

    // Setup the query
    var query = updateProductByID(req.params.pr_id, req.body);

    // Turn req.body into an array of values
    var colValues = Object.keys(req.body).map(function (key) {
      return req.body[key];
    });

    client.query(query, colValues, function(err, result) {
      if (handleErr(err, done)) return;
      done();
      sendResponse(res, result.rows[0]);
    });
  });
};

或者,如果您需要一个ORM,因为您将做很多类似上面的事情,那么您应该检查像Knex.js这样的模块

3df52oht

3df52oht2#

很好的答案已经给出了,但恕我直言,在某个方面还不够好,它们都缺乏很好的抽象。我将尝试提供更抽象的方法来使用node-postgres更新您的数据。
遵循官方文档始终是一种好的做法,以下代码结构取自node-postgres,您可以根据自己的喜好对其进行扩展:
这是我,这是您与数据库交互的地方

const { Pool } = require("pg");
const connection = require("./connection.json");
const pool = new Pool(connection);
const { insert, select, remove, update } = require("./helpers");

/**
 * The main mechanism to avoid SQL Injection is by escaping the input parameters.
 * Any good SQL library should have a way to achieve this.
 * PG library allows you to do this by placeholders `($1, $2)`
 */
module.exports = {
  query: (text, params, callback) => {
    const start = Date.now();

    return pool.query(text, params, (err, res) => {
      const duration = Date.now() - start;
      console.log("executed query", { text, duration, rows: res.rowCount });
      callback(err, res);
    });
  },

  getClient: callback => {
    pool.connect((err, client, done) => {
      const query = client.query;
      // monkey patch the query method to keep track of the last query executed
      client.query = (...args) => {
        client.lastQuery = args;
        return query.apply(client, args);
      };
      // set a timeout of 5 seconds, after which we will log this client's last query
      const timeout = setTimeout(() => {
        console.error("A client has been checked out for more than 5 seconds!");
        console.error(
          `The last executed query on this client was: ${client.lastQuery}`
        );
      }, 5000);
      const release = err => {
        // call the actual 'done' method, returning this client to the pool
        done(err);
        // clear our timeout
        clearTimeout(timeout);
        // set the query method back to its old un-monkey-patched version
        client.query = query;
      };
      callback(err, client, release);
    });
  },

  /**
   * Updates data
   *
   * entity: table name, e.g, users 
   * conditions: { id: "some-unique-user-id", ... }
   * fields: list of desired columns to update { username: "Joe", ... }
   */
  updateOne: async (entity, conditions, fields) => {
    if (!entity) throw new Error("no entity table specified");
    if (Utils.isObjEmpty(conditions))
      throw new Error("no conditions specified");

    let resp;   
    const { text, values } = update(entity, conditions, fields);

    try {
      rs = await pool.query(text, values);
      resp = rs.rows[0];
    } catch (err) {
      console.error(err);
      throw err;
    }

    return resp;
  },

  createOne: async (entity, data) => {
  },

  deleteOne: async (entity, conditions, data) => {
  },

  findAll: async (entity, conditions, fields) => {
  },

  // ... other methods
};

以下是CRUD操作的辅助方法,它们将使用准备好的值准备查询文本:

/**
 * tableName: `users`
 * conditions: { id: 'joe-unique-id', ... }
 * data: { username: 'Joe', age: 28, status: 'active', ... }
 *
 *  "UPDATE users SET field_1 = $1, field_2 = $2, field_3 = $3, ... ( WHERE ...) RETURNING *";
 */
exports.update = (tableName, conditions = {}, data = {}) => {
  const dKeys = Object.keys(data);
  const dataTuples = dKeys.map((k, index) => `${k} = $${index + 1}`);
  const updates = dataTuples.join(", ");
  const len = Object.keys(data).length;

  let text = `UPDATE ${tableName} SET ${updates} `;

  if (!Utils.isObjEmpty(conditions)) {
    const keys = Object.keys(conditions);
    const condTuples = keys.map((k, index) => `${k} = $${index + 1 + len} `);
    const condPlaceholders = condTuples.join(" AND ");

    text += ` WHERE ${condPlaceholders} RETURNING *`;
  }

  const values = [];
  Object.keys(data).forEach(key => {
    values.push(data[key]);
  });
  Object.keys(conditions).forEach(key => {
    values.push(conditions[key]);
  });

  return { text, values };
};

exports.select = (tableName, conditions = {}, data = ["*"]) => {...}
exports.insert = (tableName, conditions = {}) => {...}
exports.remove = (tableName, conditions = {}, data = []) => {...}

最后,您可以在路由处理程序中使用它,而不会扰乱代码库:

const db = require("../db");

/**
 *
 */
exports.updateUser = async (req, res) => {
  try {
    console.log("[PUT] {api/v1/users}");
    const fields = {
      name: req.body.name,
      description: req.body.description,
      info: req.body.info
    };
    const userId = req.params.id;

    const conditions = { id: userId };
    const updatedUser = await db.updateOne("users", conditions, fields);

    if (updatedUser) {
      console.log(`team ${updatedUser.name} updated successfully`);
      return res.json(updatedUser);
    }
    res.status(404).json({ msg: "Bad request" });
  } catch (err) {
    console.error(err);
    res.status(500).send({ msg: "Server error" });
  }
};

便利的公用设施:

const Utils = {};
Utils.isObject = x => x !== null && typeof x === "object";
Utils.isObjEmpty = obj => Utils.isObject(obj) && Object.keys(obj).length === 0;
7uzetpgm

7uzetpgm3#

我喜欢使用knexjs,它可以和postgre一起工作,也是一种有趣的javascript方式来编写查询(没有那些讨厌的SQL字符串操作)。
以这个方法为例,它存储了一些联系人信息,联系人信息的JSON模式在其他地方定义(验证时也很有用),结果是一个代码生成的查询,只包含传入的列。

function saveContactInfo( inputs, callback ) {
  var setObj = {};
  for( var property in inputs.contact )
  {
    //assumes properties are same as DB columns, otherwise need to use some string-mapping lookup.
    setObj[ property ] = inputs.contact[property];
  }
  setObj[ "LastModified" ] = new Date();

  var query = knex( "tblContact" ).update( setObj ).where( "contactId", inputs.contact.contactId );
  //log.debug("contactDao.saveContactInfo: " + query.toString());
  query.exec( function(err, results ){
    if(err) return callback(err);
    //Return from DB is usually an array, so return the object, not the array.
    callback( null, results[0] );
  });    
}

Knexjs也有一些漂亮的postgre-only选项(如果我没有使用MySQL,这对我来说会很有用)

col17t5w

col17t5w4#

我举个简单的例子:

async update(objectToSave) {
    const dbID = objectToSave.id;

    //get obj values only
    const args = Object.values(objectToSave);
    //get obj keys
    const keys = Object.keys(objectToSave).join(',');
    //build sql arg heys string like '$1,$2,$3'
    const argKeys = Object.keys(objectToSave).map((obj,index) => `$${index+1}`).join(',');        

    const query = `UPDATE table SET (${keys}) = (${argKeys}) WHERE id = ${dbID}`;

    try {
        const res = await client.query(query, args)
        return true;
    } catch (err) {
        console.log(err.stack)
        return false;
    }
}
guicsvcw

guicsvcw5#

创建插入查询

exports.createInsertQuery = (tablename, obj) => {
    let insert = 'insert into ' + tablename;
    let keys = Object.keys(obj);
    let dollar = keys.map(function (item, idx) { return '$' + (idx + 1); });
    let values = Object.keys(obj).map(function (k) { return obj[k]; });
    return {
        query: insert + '(' + keys + ')' + ' values(' + dollar + ')',
        params: values
    }
}

用法

let data = {firstname : 'hie' , lastname : 'jack', age : 4}
let yo = createInsertQuery('user',data) 

client.query(yo.query, yo.params ,(err,res) =>{
 console.log(res)
})

因此,像wise一样,您可以创建更新删除查询

相关问题