如何使用带有ON CONFLICT子句的knex链接诺言?

问题描述

我有两个表“ 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,})
              .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("*")

我在兑现承诺方面做错了什么吗?我该如何运作? 任何帮助将不胜感激。

解决方法

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

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