javascript 检索到的Postgres bytea数据与我插入的数据不同

zrfyljdw  于 2023-03-06  发布在  Java
关注(0)|答案(1)|浏览(137)

我有一个react前端,可以使用express将数据发送到postgres后端,我使用javascript的FileReader()从前端上传了一个pdf文件,大小为779字节,作为一个字节数组(U8intArray),字节被插入到数据库的bytea类型的表列中。
当FileReader()运行时,我的应用会将文件的数据缓冲区记录到控制台。控制台会显示文件具有以下起始字节:

(779)[37, 80, 68, 70, 45, 49, 46, ... ]

我可以从终端使用下面的sql查询来验证这些字节是否确实存储到了我的数据库中:

select left(encode(my_file, 'escape'), 50) from apps where id = 24;

终端输出:

left                        
----------------------------------------------------
{"0":37,"1":80,"2":68,"3":70,"4":45,"5":49,"6":46,
(1 row)

但问题是:当我的前端尝试从postgress检索这个字节数组数据时,字节看起来与我插入的内容不同:

// the id used is 24
axios.get("/api/get/app", { params: { id } }).then((res) => {
  console.log(res.data.my_file.data);
})

控制台输出:

(7136)[123, 34, 48, 34, 58, 51, 55, ... ]

它有7136个字节。我期望原始的[37,80,68,70,45,49,46,...]有779个字节。
当我从不同的行检索不同的pdf数据时,控制台将输出一个类似的数组,该数组再次以与上一次尝试相同的[123,34,48,34,58,51,55,...]开头,但总字节数不同,如147990。
我使用的post/get请求结构和其他类型的数据一样,比如字符串和数字,它们在前端工作得很好。但是对于bytea数据,返回到前端的输出和我输入的不一样。当我检索bytea数据时,格式必须有一些变化。

    • 因此问题是,如何检索插入的bytea数据并将其转换为原始的Uint8Array格式?**

至于代码,我的数据库中有一个名为apps的表,它存储了工作申请数据字段,其中的列包括公司名称、申请日期和简历。

//front end code to retrieve data from database
  const { id } = useParams();
  const context = useContext(Context);
  const [postingURL, setPostingURL] = useState("");
  const [companyName, setCompanyName] = useState("");
  const [jobTitle, setJobTitle] = useState("");
  const [jobDescription, setJobDescription] = useState("");
  const [jobNotes, setJobNotes] = useState("");
  const [tags, setTags] = useState("");
  const [appDate, setAppDate] = useState();
  const [elapsedDays, setElapsedDays] = useState(0);
  const [careersList, setCareersList] = useState([""]);
  const [careerNum, setCareerNum] = useState(0);
  const [newCareerNum, setNewCareerNum] = useState();
  const [resumeBytea, setResumeBytea] = useState();
  const [coverLetterBytea, setCoverLetterBytea] = useState([]);

  useEffect(() => {
    if (context.isAuthenticated && context.dbProfileState) {
      axios
        .get("/api/get/app", { params: { id } })
        .then((res) => {
          setPostingURL(res.data.posting_url);
          setCompanyName(res.data.company_name);
          setJobTitle(res.data.job_title);
          setJobDescription(res.data.job_description);
          setJobNotes(res.data.job_notes);
          setTags(String(res.data.tags));
          setCareerNum(
            newCareerNum >= 0
              ? newCareerNum
              : dbProfile.careers_list.indexOf(res.data.career_name)
          );
          let appDate = new Date(res.data.application_date);
          let currDate = new Date();
          let elapsed =
            Math.ceil((currDate - appDate) / (1000 * 3600 * 24)) - 1;
          setAppDate(appDate);
          setElapsedDays(elapsed);
          setResumeBytea(res.data.resume_file)
          // console.log(res.data.resume_file)
          setCoverLetterBytea(res.data.cover_letter_file.data);
        })
        .catch((err) => console.log(err));
    }
  }, [context, id]);

}
//back end express/node code to send table row data to front end 
router.get("/api/get/app", (req, res) => {
  const appId = req.query.id;
  pool.query(
    `SELECT * FROM apps WHERE app_id = $1`,
    [appId],
    (q_err, q_res) => {
      res.json(q_res.rows[0]);
    }
  );
  console.log("Queried row id:", appId);
});

表格结构:

CREATE TABLE apps (
  app_id SERIAL UNIQUE,
  username TEXT UNIQUE REFERENCES users(username),
  career_name TEXT,
  posting_url TEXT,
  company_name TEXT NOT NULL,
  job_title TEXT NOT NULL,
  job_description TEXT,
  job_notes TEXT,
  resume_file BYTEA, 
  cover_letter_file BYTEA,
  tags TEXT [],
  application_date TEXT,
  PRIMARY KEY(app_id)
);
t3psigkw

t3psigkw1#

好吧,我知道了。
postgres中的bytea数据是二进制格式的,在发送之前需要从后端将其编码为文本格式。
因此,不要使用SELECT * sql查询发送整行,如下所示:

router.get("/api/get/app", (req, res) => {
  const appId = req.query.id;
  pool.query(
    `SELECT * FROM apps WHERE app_id = $1`,
    [appId],
    (q_err, q_res) => {
      res.json(q_res.rows[0]);
    }
  );
  console.log("Queried row id:", appId);
});

我必须修改sql查询以使用encode()函数,如下所示:

SELECT app_id, username, career_name, posting_url, company_name, job_title, 
    job_description, job_notes, encode(resume_file::bytea, 'escape') as "resume_file", encode(cover_letter_file::bytea, 'escape') as "cover_letter_file", tags, application_date FROM apps WHERE app_id = $1

然后,前端将接收解析的数据对象“res”,其中行数据的res.data.resume_file部分将是一个字符串,如下所示:

'{"0":37,"1":80,"2":68,"3":70,"4":45,"5":49,"6":46, ...}'

然后需要使用JSON.parse()将其转换为一个对象,然后将其转换为一个数组,再转换为一个Uint8Array,如下所示:

const resumeData = JSON.parse(res.data.resume_file);
let resumeByteA = Object.keys(resumeData).map((key) => resumeData[key]);
resumeByteA = new Uint8Array(resumeByteA);

相关问题