I'm trying to determine if a user has voted on a question
. The user clicks on an upvote/downvote button which makes a request to an API that pulls out their id
form a cookie and then stores it within an upvoters
or downvoters
array. The upvote/downvote logic works as expected -- no problem there -- however, I'm having trouble determining whether or not the upvoters
or downvoters
array contains their id
when the user queries questions by a specific tag.
The question model:
Column │ Type │ Modifiers
─────────────────────────┼───────────────────────────┼──────────────────────────────────────────────
key │ Serial │ PRIMARY KEY
userid │ UUID │ NOT NULL REFERENCES users(id)
date │ TIMESTAMP │ WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
answered │ BOOLEAN │ DEFAULT FALSE
views │ INTEGER │ DEFAULT 0
upvoters | TEXT[] | DEFAULT array[]::text[]
downvoters | TEXT[] | DEFAULT array[]::text[]
title | TEXT | NOT NULL DEFAULT ''
uniquetitle | VARCHAR | NOT NULL DEFAULT ''
body | TEXT | NOT NULL DEFAULT ''
tags | TEXT[] | DEFAULT array[]::text[]
comments | JSONB |
The API endpoint:
import get from "lodash.get";
import isEmpty from "lodash.isempty";
import db from "~db"; // connection to Postgres using pg-promise
const findAllQuestionsByTagLimitAndOffset = `
SELECT
questions.key,
questions.userid,
questions.date,
questions.body,
questions.answered,
questions.views,
cardinality(questions.upvoters)-cardinality(questions.downvoters) as votes,
EXISTS(
SELECT FROM questions WHERE questions.upvoters @> $4
) as upvoted, // check whether or not the logged in user has upvoted this question
EXISTS(
SELECT FROM questions WHERE questions.upvoters @> $4
) as downvoted, // check whether or not the logged in user has downvoted this question
questions.title,
questions.uniquetitle,
questions.tags,
users.username, // appends original poster's username
users.reputation as userrep, // appends original poster's rep
users.key as userkey // appends original poster's id
FROM questions
INNER JOIN users ON questions.userid=users.id
WHERE questions.tags @> $1
ORDER BY questions.date DESC
LIMIT $2
OFFSET $3
`;
/**
* Fetches questions by tag.
*
* @function fetchNewestQuestionsByTag
* @param {object} req - request object
* @param {object} res - response object
* @returns {array} data - questions that contain the queried tag with original poster populated data and some logged in user data
* @throws {string} err
*/
const fetchNewestQuestionsByTag = async (req, res) => {
try {
const { tag } = req.query;
if (!tag) throw String("Unable to locate questions because the tag is not valid.");
const userid = get(req.session, ["id"]);
const data = await db.any(findAllQuestionsByTagLimitAndOffset, [
[tag],
10,
0,
[userid],
]);
if (isEmpty(data)) throw String("Unable to locate any questions.");
res.status(201).send(data);
} catch (err) {
res.status(404).send(err);
}
};
Here's how the question
looks after an upvote:
answered: false
body: "Test"
date: "2020-06-19T20:24:46.496Z"
downvoters: []
comments: []
title: "Test Title"
tags: ["reactjs"]
uniquetitle: "test-title"
upvoters ["d17a33f4-b26a-11ea-9372-131fa959a01b"] // logged in user id is stored
userid: "d17a33f4-b26a-11ea-9372-131fa959a018"
views: 1
After a user has upvoted and refreshes the page and/or queries the question they upvoted by a tag, the following (incorrect) data structure is returned:
answered: false
body: "Test"
date: "2020-06-19T20:24:46.496Z"
downvoted: false
tags: ["reactjs"]
title: "Test Title"
uniquetitle: "test-title"
upvoted: false // this should be true as the logged in user is "d17a33f4-b26a-11ea-9372-131fa959a01b" and their id is contained within this array, yet it is still false
userid: "d17a33f4-b26a-11ea-9372-131fa959a018"
userkey: 1
username: "Matt"
userrep: 0
views: 1
votes: 1
The problem is that these queries always return false:
EXISTS(
SELECT FROM questions WHERE questions.upvoters @> $4
) as upvoted,
EXISTS(
SELECT FROM questions WHERE questions.downvoters @> $4
) as downvoted,
I've tried the following and none of them returns the correct boolean status:
How to make a select with array contains value clause in psql
Check if value exists in Postgres array
Postgres: check if array field contains value?
What am I doing wrong?