如何使用 knex 和 ON CONFLICT 子句链接承诺?

how to chain promises using knex with the ON CONFLICT clause?

我有两个 tables '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)
----------------------------------------------------
          |        |            |              
          |        |            |              
          |        |            |                      

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

一旦 ip_address 插入 table 就会生成 user_temp_id 除非 IP 地址已经存在于 table 中(我正在使用 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_id 的 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("*")

我在链接 promise 时做错了什么吗?我怎样才能让它发挥作用? 任何帮助将不胜感激。

我找到答案了。第一个承诺(我使用 'ON CONFLICT' 子句的承诺不只是 return 具有 temp_user_id 的对象数组,就像我预期的那样,而是 return编辑了一个包含许多属性的对象,其中包括一个名为“行”的 属性,其中包含 returned temp_user_id 值。

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