【问题标题】:Knex Raw Select Postgresql with variableKnex Raw 选择带有变量的 Postgresql
【发布时间】:2020-04-17 15:18:45
【问题描述】:

我可以在 knex 查询中使用变量吗? db.raw(select usr_vote.vote where usr_vote.user.id = ${loggedInUserId}) 有什么问题?其他一切正常。

在现在不起作用的 db.raw 中,我正在尝试使用一个变量 (loggedInUserId) 来获取登录用户对问题的投票历史记录(他们可以投票/投票,因此该值为 -1或 1 或空)。提前感谢您的帮助!

有 4 个表格看起来像:

askify_users

  • 身份证
  • 用户名

askify_questions

  • 身份证
  • 标题
  • 身体
  • 标签
  • 创建日期
  • user_id(FK 参考 askify_users.id)

askify_answers

  • 身份证
  • 回答
  • question_id(FK 参考 askify_question.id)
  • user_id(FK 参考 askify_users.id)

askify_question_votes

  • 列表项
  • question_id(FK 参考 askify_questions.id)
  • user_id(FK 参考 askify_users.id)
  • 投票(-1 或 1)
  • 主键(question_id、user_id)

getAllQuestions(db, loggedInUserId) {
    return db
      .from('askify_questions AS q')
      .select(
        'q.id AS question_id',
        'q.title AS question_title',
        'q.body AS question_body',
        'q.date_created AS date_created',
        'q.tags',
        db.raw(
          `count(DISTINCT ans) AS number_of_answers`
        ),
        db.raw(
          `SUM(DISTINCT usr_vote.vote) AS sum_of_votes`
        ),
        db.raw(
          `select usr_vote.vote where usr_vote.user_id = ${loggedInUserId}`
        ),
        db.raw(
          `json_strip_nulls(
            json_build_object(
              'user_id', usr.id,
              'user_name', usr.user_name,
              'full_name', usr.full_name,
              'date_created', usr.date_created
            )
          ) AS "user"`
        )
      )
      .leftJoin(
        'askify_answers AS ans',
        'q.id',
        'ans.question_id'
      )
      .leftJoin(
        'askify_users AS usr',
        'q.user_id',
        'usr.id'
      )
      .leftJoin(
        'askify_question_vote AS usr_vote',
        'q.id',
        'usr_vote.question_id'
      )
      .groupBy('q.id', 'usr.id')
  },

查询应如下所示。除了 'user_vote_history' 之外的所有东西都在工作。

  serializeQuestion(question) {
    const { user } = question
    return {
      id: question.question_id,
      question_title: xss(question.question_title),
      question_body: xss(question.question_body),
      date_created: new Date(question.date_created),
      number_of_answers: Number(question.number_of_answers) || 0,
      user_vote_history: question.user_vote_history,
      sum_of_votes: Number(question.sum_of_votes),
      tags: xss(question.tags),
      user: {
        user_id: user.user_id,
        user_name: user.user_name,
        full_name: user.full_name,
        user_vote: user.user_vote,
        date_created: new Date(user.date_created)
      },
    }
  },

【问题讨论】:

  • 您使用什么语言? ${loggedInUserId} 似乎不合适,因为 javascript 变量没有美元前缀
  • Javascript 模板文字,注意反引号
  • 注意,当您将 .raw 与客户端提供的值一起使用时,您的应用程序会暴露给 SQL 注入。 .raw 接受具有绑定值的数组的第二个参数。
  • db.raw( 'select usr_vote.vote where usr_vote.user_id = ?', [loggedInUserId] )

标签: postgresql knex.js


【解决方案1】:

我注意到@felixmosh 在这里关于绑定值是正确的,但只是为了详细说明:这里的关键是当字符串替换发生时。如果你这样做:

db.raw(`SELECT vote WHERE user_id = ${loggedInUserId}`)

只要 JS 解释器到达这一行,就会在 JavaScript 中进行替换。数据库引擎与loggedInUserId 中的内容无关,Knex 也没有:您实际上是在绕过所有内置保护。

稍微好一点的是:

db.raw("SELECT vote WHERE user_id = ?", loggedInUserId)

这允许 Knex 转义 loggedInUserId 中的字符串。如果您愿意,可以使用命名绑定:

db.raw("SELECT vote WHERE user_id = :loggedInUserId", { loggedInUserId })

但是,通过使用 Knex 已经为子查询提供的工具,可以轻松避免所有这些与绑定有关的问题:只需将子查询放入函数中即可。

db
  .from("askify_questions AS q")
  .select(
    "q.id AS question_id",
    qb => qb.select("usr_vote.vote").where({ user_id: loggedInUserId })
  )
  .leftJoin(
    "askify_question_vote AS usr_vote",
    "q.id",
    "usr_vote.question_id"
  );

qb 参数代表“查询生成器”,由 Knex 传递给您的函数。它的行为与您的 db 对象非常相似。

这会生成类似于以下的 SQL:

SELECT
  "q"."id" AS "question_id",
  (
    SELECT "usr_vote"."user_id" WHERE "user_id" = ?
  ) 
  FROM "askify_questions AS q"
  LEFT JOIN "askify_question_vote" AS "usr_vote"
    ON "q"."id" = "usr_vote"."question_id"

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 2011-06-21
    • 2013-12-16
    • 1970-01-01
    • 2015-09-24
    • 2011-03-11
    • 2020-08-27
    相关资源
    最近更新 更多