【问题标题】:how to chain promises using knex with the ON CONFLICT clause?如何使用带有 ON CONFLICT 子句的 knex 链接承诺?
【发布时间】:2020-12-07 13:02:29
【问题描述】:

我有两个表 'temp_users' 和 'ratings'

         TABLE 1 (temp_users)

temp_user_id(pkey) | ip_address | total_ratings
-----------------------------------------
                   |            |              
                   |            |              
                   |            |              
     

         TABLE 2 (ratings)

rating_id | rating | product_id | temp_user_id(fkey)
----------------------------------------------------
          |        |            |              
          |        |            |              
          |        |            |                      

我正在尝试这样做,以便一旦用户尝试对产品进行评分,就会使用他们的 IP 地址创建一个 temp_user。

一旦将 ip_address 插入表中,就会生成 user_temp_id,除非该 ip 地址已存在于表中(我正在使用 postgres ON CONFLICT 来完成此操作,如下面的代码所示)。

一旦 temp_user 对产品进行评分,他们就无法再次对其进行评分。换句话说,一个 temp_user 只能对同一个产品进行一次评分。

当我使用 'ON CONFLICT' 或 'WHERE NOT EXIST' 子句时,我完成此操作的代码不起作用,当我允许插入相同 IP 地址的重复项时工作正常。我的代码如下:

app.post("/rating", (req, res) => {
  const ip =                              // <==== this is just to get the ip address. works fine.
    (req.headers["x-forwarded-for"] || "").split(",").pop().trim() ||
    req.connection.remoteAddress ||
    req.socket.remoteAddress ||
    req.connection.socket.remoteAddress; 
  const { rating, product_id } = req.body;

 knex
      .raw(                   // <=== inserts ip and temp_user_id. returns temp_user_id
        `INSERT INTO temp_users(ip_address)    
              VALUES ('${ip}')
              ON CONFLICT (ip_address)
              DO UPDATE SET total_ratings = EXCLUDED.total_ratings
              RETURNING temp_user_id`
      )
    .then((results) => {        // <=== counts the ratings to check later if user rated before
      return knex("ratings")
        .count("*")
        .as("total")
        .where({
          product_id: product_id,
          temp_user_id: results[0].temp_user_id,
        })
        .then((data) => {         // <=== check if user rated before, if not insert new user
          if (data[0].count > 0) {
            return res.status(400).json("user already rated");
          } else {
            return knex("ratings")
              .returning("*")
              .insert({
                rating: rating,
                product_id: product_id,
                temp_user_id: results[0].temp_user_id,
              })
              .then((response) => res.json(response))
              .catch((err) => err);
          }
        });
    })
    .then((response) => res.json(response))
    .catch((err) => err);
});

如果我在下面使用此代码,代码可以完美运行,但它会插入多个具有不同 temp_user_ids 的 IP 地址,这不是我想要的。

所以通过切换这部分代码...

 knex
      .raw(
        `INSERT INTO temp_users(ip_address)
              VALUES ('::5')
              ON CONFLICT (ip_address)
              DO UPDATE SET total_ratings = EXCLUDED.total_ratings
              RETURNING temp_user_id`
      )

到这里……

 knex("temp_users")
   .insert({
     ip_address: ip,
    })
    .returning("*")

我在链接承诺方面做错了什么?我怎样才能让它工作? 任何帮助将不胜感激。

【问题讨论】:

  • 你有一个内部和一个外部.then(response =&gt; res.json(response))。如果一切都成功,两者都将(尝试)执行,外部的对内部的res.json(response)返回的任何内容进行操作。
  • 请注意.catch(err =&gt; err)err 发送到成功路径。要么不接,要么接再扔。

标签: postgresql express promise knex.js


【解决方案1】:

我已经找到答案了。第一个承诺(我使用 'ON CONFLICT' 子句的那个不只是像我预期的那样返回一个带有 temp_user_id 的对象数组,而是返回一个包含许多属性的对象,包括一个名为“rows”的属性" 其中包含返回的 temp_user_id 值。

所以我只需要将代码更改为 results.rows[0].temp_user_id 而不是 results[0].temp_user_id。

【讨论】:

    猜你喜欢
    • 2017-11-18
    • 2021-11-07
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2020-07-20
    • 2014-05-22
    相关资源
    最近更新 更多