【问题标题】:pg-promise resolving multiple queries in a map functionpg-promise 解决 map 函数中的多个查询
【发布时间】:2020-10-15 08:27:12
【问题描述】:

pg-promise transaction with dependent queries in forEach loop gives warning Error: Querying against a released or lost connection 相关,我现在正尝试从地图函数中返回多个查询

const {db} = require('../db')

async function get(id) {
  return await db
    .task(async t => {
      const items = await t.any(`SELECT i.* FROM item i WHERE i.parent_id = $1#`, id)
      const itemDetails = items.map(async item => {
        const layers = await t.any(`SELECT l.* FROM layer l WHERE l.item_id = $1#`, item.id)
        const bases = await t.any(`SELECT b.* FROM base b WHERE b.item_id = $1#`, item.id)
        return [layers, bases]
      })
      // Not resolving properly!
      await t.batch(itemDetails.flat())

      return {items: items, itemDetails: itemDetails}
    })
    .then(data => {
      return {success: true, response: data}
    })
    .catch(error => {
      return {success: false, response: error.message || error}
    })
}

但是,我不确定如何正确解决多个查询(层和基)。如果我返回一个或另一个,根据链接的问题,我可以在继续之前批量解决一系列承诺。但是,在每次地图迭代中返回多个查询时,我不确定如何在继续之前正确解决所有问题。

【问题讨论】:

    标签: node.js postgresql pg-promise


    【解决方案1】:

    谢谢!因此,要完全分离关注点,我应该这样做:

    function get(id) {
      return db.task(async t => {
          const items = await t.any(`SELECT i.* FROM item i WHERE i.parent_id = $<id>`, {id});
          const itemDetails = items.map(async item => {
            const layers = await t.any(`SELECT l.* FROM layer l WHERE l.item_id = $<id>`, item);
            const bases = await t.any(`SELECT b.* FROM base b WHERE b.item_id = $<id>`, item);
            return {layers, bases};
          });
    
          const details = await t.batch(itemDetails);
    
          return {items, details};
        })
    

    然后当我调用这个函数时,说要将它添加到express api,这样做

      router.get('/:id', async (req, res, next) => {
        const all = await get(req.params.id)
          .then(data => {
            return {success: true, response: data}
          })
          .catch(error => {
            return {success: false, response: error.message || error}
          })
        res.json(all)
      })
    

    【讨论】:

    • 是的,看起来更好。如果你还想改进它,你的整个 get 可以只做一个查询,使用 Postgres JSON 函数 like here
    【解决方案2】:

    您正在以一种奇怪的方式做一些事情。这是修正版:

    function get(id) {
      return db.task(async t => {
          const items = await t.any(`SELECT i.* FROM item i WHERE i.parent_id = $<id>`, {id});
          const itemDetails = items.map(async item => {
            const layers = await t.any(`SELECT l.* FROM layer l WHERE l.item_id = $<id>`, item);
            const bases = await t.any(`SELECT b.* FROM base b WHERE b.item_id = $<id>`, item);
            return {layers, bases};
          });
    
          const details = await t.batch(itemDetails);
    
          return {items, details};
        })
        .then(data => {
          return {success: true, response: data};
        })
        .catch(error => {
          return {success: false, response: error.message || error};
        })
    }
    

    请注意,您在这里仍然会有各种顾虑,因为 .then-&gt;.catch 应该在此处的 get 函数之外,即避免将数据库逻辑与 HTTP 控制器混合。

    【讨论】:

      猜你喜欢
      • 2019-02-11
      • 2021-04-11
      • 2018-02-19
      • 2018-01-24
      • 2016-04-03
      • 2017-10-14
      • 2020-01-17
      • 2019-01-04
      相关资源
      最近更新 更多