0

I am following the guide at https://github.com/nsebhastian/react-node-postgres. Against the comments in below that blog, I can confirm that the full tutorial is working, see this documented at TypeError: Cannot read property 'rows' of undefined.

The ADD and the DELETE command work, and the SELECT to show the table merchant.

The blog ends with:

I’ll leave you the implementation of the UPDATE query as an exercise.

And I thought, why not try that? This was hours ago...

I just took the exact files provided in the GitHub repository.

In the "/node-postgres" directory, I changed:

  • "index.js" by adding at the bottom:
app.put('/merchants', (req, res) => {
  merchant_model
    .updateMerchant(req.body)
    .then((response) => {
      res.status(200).send(response);
    })
    .catch((error) => {
      res.status(500).send(error);
    });
});
  • "merchant_model.js" by adding and changing at the bottom, almost copying the createMerchant function of the guide.

The original createMerchant function:

const createMerchant = (body) => {
  return new Promise(function (resolve, reject) {
    const { name, email } = body;

    pool.query(
      'INSERT INTO merchants (name, email) VALUES ($1, $2) RETURNING *',
      [name, email],
      (error, results) => {
        if (error) {
          reject(error);
        }
        resolve(
          `A new merchant has been added added: ${JSON.stringify(
            results.rows[0]
          )}`
        );
      }
    );
  });
};

Now the new updateMerchant function:

const updateMerchant = (body) => {
  return new Promise(function (resolve, reject) {
    const { id, name } = body;
    pool.autoCommit = true;

    pool.query(
      'UPDATE merchants SET name = "$2" WHERE id = $1',
      [id, name],
      (error, results) => {
        if (error) {
          reject(error);
        }
        resolve(
          `A merchant has been updated: ${JSON.stringify(results.rows[0])}`
        );
      }
    );
  });
};

module.exports = {
  getMerchants,
  createMerchant,
  deleteMerchant,
  updateMerchant,
};

In the /node-postgres/react-postgres directory, I changed (using PUT method for UPDATE because of Need help about @Get @Post @Put @Delete in Restful webservice or Explain and example about 'get', 'delete', 'post', 'put', 'options', 'patch', 'head' method?):

  • "App.js" by adding and changing at the bottom:
function updateMerchant() {
  let id = prompt('Enter merchant ID');
  let name = prompt('Enter merchant name');

  fetch('http://localhost:3001/merchants', {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ id, name }),
  })
    .then((response) => {
      return response.text();
    })
    .then((data) => {
      alert(data);
      getMerchant();
    });
}

return (
  <div>
    {merchants ? merchants : 'There is no merchant data available'}
    <br />
    <button onClick={createMerchant}>Add</button>
    <br />
    <button onClick={deleteMerchant}>Delete</button>
    <br />
    <button onClick={updateMerchant}>Update</button>
  </div>
);

When I click on Update in the React app in the browser at localhost:3000, I get the right questions for id and name, running ... 'UPDATE merchants SET name = "$2" WHERE id = $1', [id, name] ...:

enter image description here

and:

enter image description here

which then throws the error:

enter image description here

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Error</title> </head> <body> <pre>Cannot PUT /merchants</pre> </body> </html>

which is nothing but this error message in html (I only need to format it as a markdown quote here to get this):

Error
Cannot PUT /merchants

The error stays the same when I run the UPDATE without parametrisation:

... 'UPDATE merchants SET name = "test" WHERE id = 2', [id, name] ...

I have tried switching from PUT method to POST, but then every UPDATE just adds a new merchant with a new id and a null value for the email, see the screenshot above. The record in SQL is not updated by the UPDATE command, you see the change in the table in the first lines in real-time.

What should I do to get the UPDATE to work?

UPDATE:

As answer + comment show, using "" makes a field. But that does not solve the issue, I changed the code to 'UPDATE merchants SET name = $2 WHERE id = $1' since quotation marks are not needed for parameters and I get the error in in "node.js" terminal, stopping the "node.js" service:

my_user@MY_PC:~/my_project/node-postgres$ node index.js
App running on port 3001.
/home/my_user/my_project/node-postgres/merchant_model.js:61
      resolve(`A merchant has been updated: ${JSON.stringify(results.rows[0])}`)
                                                                     ^

TypeError: Cannot read property 'rows' of undefined
    at pool.query (/home/my_user/my_project/node-postgres/merchant_model.js:61:70)
    at Query.client.query [as callback] (/home/my_user/my_project/node-postgres/node_modules/pg-pool/index.js:387:18)
    at Query.handleError (/home/my_user/my_project/node-postgres/node_modules/pg/lib/query.js:128:19)
    at Client._handleErrorMessage (/home/my_user/my_project/node-postgres/node_modules/pg/lib/client.js:335:17)
    at Connection.emit (events.js:198:13)
    at parse (/home/my_user/my_project/node-postgres/node_modules/pg/lib/connection.js:114:12)
    at Parser.parse (/home/my_user/my_project/node-postgres/node_modules/pg-protocol/dist/parser.js:40:17)
    at Socket.stream.on (/home/my_user/my_project/node-postgres/node_modules/pg-protocol/dist/index.js:11:42)
    at Socket.emit (events.js:198:13)
    at addChunk (_stream_readable.js:288:12)

UPDATE2:

As I has been asked for in the comments, I switched on the log for this test database. Here are the last queries before it worked:

2021-09-20 23:33:09.071 CEST [2637] my_user@my_database LOG:  statement: SELECT * FROM merchants ORDER BY id ASC
2021-09-20 23:33:44.346 CEST [2641] my_user@my_database ERROR:  bind message supplies 2 parameters, but prepared statement "" requires 0
2021-09-20 23:33:44.346 CEST [2641] my_user@my_database STATEMENT:  UPDATE merchants SET name = 'test' WHERE id = 2
2021-09-20 23:37:37.465 CEST [2674] my_user@my_database LOG:  statement: SELECT * FROM merchants ORDER BY id ASC
2021-09-20 23:37:38.586 CEST [2674] my_user@my_database LOG:  statement: SELECT * FROM merchants ORDER BY id ASC
2021-09-20 23:37:46.853 CEST [2674] my_user@my_database ERROR:  bind message supplies 2 parameters, but prepared statement "" requires 1
2021-09-20 23:37:46.853 CEST [2674] my_user@my_database STATEMENT:  UPDATE merchants SET name = '$2' WHERE id = $1
2021-09-20 23:41:16.399 CEST [2704] my_user@my_database LOG:  statement: SELECT * FROM merchants ORDER BY id ASC
2021-09-20 23:41:31.879 CEST [2706] my_user@my_database ERROR:  bind message supplies 2 parameters, but prepared statement "" requires 1
Kartikey
  • 4,516
  • 4
  • 15
  • 40
questionto42
  • 7,175
  • 4
  • 57
  • 90
  • Is the record in SQL being updated? – Joe Lissner Sep 20 '21 at 18:09
  • @JoeLissner I edited the question. The table is updated in real-time as I can see from the other tests, thus, `UPDATE` does not change the database. – questionto42 Sep 20 '21 at 18:13
  • 1
    try it like this: `... 'UPDATE merchants SET name = $2 WHERE id = $1', [2, 'test'] ...`. You shouldn't need any quotes when using parameters. – Joe Lissner Sep 20 '21 at 21:47
  • @JoeLissner Right you are! When I copied it directly from the createMerchant function, the function did not have any quoatation marks either. I just happened to add them during testing around since somewhere had to be an issue somehow. But the answer about using the wrong "" was right as well, of course. – questionto42 Sep 20 '21 at 22:01

3 Answers3

1

The issue is likely with the statement 'UPDATE merchants SET name = "$2" WHERE id = $1'

In Postgres, a double quote refers to a field name, not a value. You need to use single quotes.

JGH
  • 15,928
  • 4
  • 31
  • 48
  • ...and the 2nd issue is that you are not seeing the real error message that would have helped you debug the issue. Don't hide them but log them... and look at your logs! – JGH Sep 20 '21 at 18:14
  • I changed it to `"UPDATE merchants SET name = '$2' WHERE id = $1"`, same error. Same error also without quotation marks: `UPDATE merchants SET name = $2 WHERE id = $1`. – questionto42 Sep 20 '21 at 18:18
  • I am new to this, I will look up how to catch the logs - and not "hide them", I do not know yet what was meant here. And as to the error: do you mean the error says that I do not have the right to update the table? Because that would be strange, since I can delete and add. – questionto42 Sep 20 '21 at 18:21
  • 1
    it could be (`update` privilege is distinct from `insert`/`delete`), but without seeing the real error message it is only shots in the dark. For example using the double quotes you should have gotten a message similar to `ERROR: column "test" does not exist` – JGH Sep 20 '21 at 18:24
1

Here is everything you need to get the merchants table updating correctly..

app.put('/merchants/:id', (req, res) => {
  merchant_model.updateMerchant(req.body)
    .then(response => {
      res.status(200).send(response);
    })
    .catch(error => {
      res.status(500).send(error);
    })
})




const updateMerchant = (body) => {
  return new Promise(function(resolve, reject) {
    const {
      id,
      name,
      email
    } = body
    pool.query('UPDATE merchants SET name = $2, email = $3 WHERE id = $1', [id, name, email], (error, results) => {
      if (error) {
        reject(error)
      }
      resolve(`Merchant ${id} updated`)
    })
  })
}



function updateMerchant() {
  let id = prompt("Enter Merchant Id");
  let name = prompt("Enter merchant name");
  let email = prompt("Enter merchant email");
  fetch(`http://localhost:3001/merchants/${id}`, {
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        id,
        name,
        email
      }),
    })
    .then((response) => {
      return response.text();
    })
    .then((data) => {
      alert(data);
      getMerchant();
    });
}
  • Hi, your answer addressed the question, and that's good. Keep in mind, however, that is better to explain what you have done for resolving the issue; we are all here to learn – pierpy Apr 21 '23 at 05:04
0

There were many wrong steps that caused this issue.

  1. I copied the code of the createMerchant function and forgot to change the

     resolve(`A merchant has been updated: ${JSON.stringify(results.rows[0])}`)
    

The results.rows are empty if I just update something, they only have a value when you create a new row. Now it works with:

const updateMerchant = (body) => {
  return new Promise(function(resolve, reject) {
    const { id, name } = body
    
    pool.query("UPDATE merchants SET name = $2 WHERE id = $1 RETURNING *", [id, name], (error, results) => {        
      if (error) {
        reject(error)
      }
      resolve(`Merchant updated with ID: ${id}, changed name to ${name}.`)
    })
  })
}
  1. But when I now take the old and wrong version with the wrong results.rows, I also get that same error, even with the right quotation marks:
/home/my_user/my_project/node-postgres/merchant_model.js:61
      resolve(`A merchant has been updated: ${JSON.stringify(results.rows[0])}`)
                                                                     ^

TypeError: Cannot read property 'rows' of undefined
    at pool.query (/home/my_user/my_project/node-postgres/merchant_model.js:61:70)
    at Query.client.query [as callback] (/home/my_user/my_project/node-postgres/node_modules/pg-pool/index.js:387:18)
    at Query.handleError (/home/my_user/my_project/node-postgres/node_modules/pg/lib/query.js:128:19)
    at Client._handleErrorMessage (/home/my_user/my_project/node-postgres/node_modules/pg/lib/client.js:335:17)
    at Connection.emit (events.js:198:13)
    at parse (/home/my_user/my_project/node-postgres/node_modules/pg/lib/connection.js:114:12)
    at Parser.parse (/home/my_user/my_project/node-postgres/node_modules/pg-protocol/dist/parser.js:40:17)
    at Socket.stream.on (/home/my_user/my_project/node-postgres/node_modules/pg-protocol/dist/index.js:11:42)
    at Socket.emit (events.js:198:13)
    at addChunk (_stream_readable.js:288:12)

The problem is that I have often not restarted node.js, but only reactJS. I was used to getting real-time updates for all of the js files when I was on node.js backend, but on the frontend, this is of course different! You need to restart node.js to apply the changes for the frontend. When restarting node.js, the "React App" as the frontend can run further and will find the backend as soon as it runs again.

  1. Only when I had restarted node.js, I got the real errors of the new setting, including the wrong "" quotation marks.

  2. Therefore, the original error Cannot PUT /merchant could be something from a slightly older version of the project today where I experimented with adding parameters to the fetch address like fetch(\http://localhost:3001/merchants/${id}`, {` and other tests. I lack the nerves and time to reproduce this. Perhaps, it might still be covered by the log output at the bottom of the question right before it finally worked, saying:

     2021-09-20 23:33:44.346 CEST [2641] my_user@my_database ERROR:  bind message supplies 2 parameters, but prepared statement "" requires 0
    

At least, it is solved now, the log output at the first working UPDATE query:

2021-09-20 23:47:51.648 CEST [2792] my_user@my_database LOG:  execute <unnamed>: UPDATE merchants SET name = $2 WHERE id = $1 RETURNING * 2021-09-20 23:47:51.648 CEST [2792] my_user@my_database DETAIL:  parameters: $1 = '2', $2 = 'asdf' 2021-09-20 23:48:03.374 CEST [2795] my_user@my_database LOG:  statement: SELECT * FROM merchants ORDER BY id ASC

Example screenshots, updating ID 2:

enter image description here enter image description here

Press F5:

enter image description here

questionto42
  • 7,175
  • 4
  • 57
  • 90