【问题标题】:TypeORM Postgres WHERE ANY or IN With QueryBuilder Or Find?TypeORM Postgres WHERE ANY 或 IN 使用 QueryBuilder 或查找?
【发布时间】:2018-11-15 05:55:15
【问题描述】:

我一直试图弄清楚如何选择 Postgres 数据库中的每条记录,这些记录在具有整数数组的列中包含某个 id。我对这一切都很陌生,但我相信我想要一个看起来像这样的 SQL 语句:

SELECT * FROM members WHERE 2 = ANY(skill_id_array);

skill_id_array 列中的数据如下所示:{1,4,7}。

我从 Angular 前端传入一个 id,例如 2 作为参数。登录终端显示 select 语句的结尾,但它失败了:

... WHERE $1 ANY (skill_id_array) -- PARAMETERS: [2]

我认为问题在于我试图将变量传递到代码中,但它讨厌它。请注意,我一直在尝试 find 方法和 QueryBuilder。产生的错误在 cmets 中。 (完整的 CRUD 工作正常,所以我的整体设置很好。)

这很好用,但我知道这有一个 sql 注入问题:

const membersBySkill = await this.entityManager.query(
      `SELECT * FROM members WHERE ${integerId} = ANY(members.skill_id_array)`
    );

这可行,但我不确定是否存在 sql 注入问题,而且我想使用 TypeORM find 或 QueryBuilder。

  const sql = 'SELECT * FROM members WHERE '+ integerId + ' = ANY(skill_id_array)';
  const membersBySkill = await this.entityManager.query(sql);

为我服务:

import {Any} from "typeorm";

  async getMembersBySkill(id) {
    const integerId = parseInt(id, 10); // convert id to integer for Postgres array.
    // console.log('skill_id in service', integerId);
    // Find one skill id in an array of id's.
/*
    const membersBySkill = await this.connection.getRepository(Members).find({
      skill_id_array: Any(integerId)
    });
    //  This results in an IDE error.  It doesn't like a number as 
    //  the ANY param.  "{integerId: number} is not assignable to
    //  parameter type '{}[] | FindOperator<{}>'.
    //  In terminal: error: could not find array type for data type integer[].  
    //  However, the db has integers.
*/

    const membersBySkill = await getRepository(Members)
      .createQueryBuilder("members")
      .select('*')
      .where(":id IN (skill_id_array)", {id: integerId})
      .getMany();
      // SELECT * FROM "members" "members" WHERE $1 IN (skill_id_array) -- PARAMETERS: [2]
      // server console: error: malformed array literal: "2"

    console.log('membersBySkill: ', membersBySkill);
    return membersBySkill;
  }

实体:

  @Column('int', { array: true, nullable: true})
  skill_id_array: number[];

Postgres 列类型:integer[]

每次更改时我都会停止并启动 Nestjs 服务器。

【问题讨论】:

    标签: typeorm


    【解决方案1】:

    目前可以使用语法

    .where("id IN(:...ids)", { ids: [1,2,3] })
    

    【讨论】:

    • 问题是变量的使用,而不是硬编码的数组。我已经解决了这个问题。我看到您是新人,但否则我会否决您的回答。在尝试回答之前,请务必了解问题和其他答案。对你最好。
    • 你可以为所欲为
    • @Preston 他的回答是正确的,你不明白。此解决方案可以使用或不使用硬编码数组。
    • @Preston 答案是正确的,你不明白。只需放入一个数组变量而不是硬编码的变量。有那么难吗?
    • 这将使用 QueryBuilder 但不能使用原始 sql 查询的查询方法
    【解决方案2】:

    Web 上的许多地方都说 SQL 运算符 IN 和 ANY 几乎是等价的。因此,我认为它们的设置几乎相同,只是 ANY 需要'='。错了,但花了很长时间才弄明白。

    QueryBuilder 中的任何设置都有效:

    const membersBySkill = await getRepository(Members)
          .createQueryBuilder()
          .where(':id = ANY (skill_id_array)', {id: integerId})
          .getMany();
    

    以前我使用 TypeORM Find Options 文档中的“Any”设置,因为 QueryBuilder 文档中(还)没有解决 ANY。这似乎是当时要走的路,但不要混合它们。

    TypeORM 主要贡献者@pleerock 建议在此设置中使用别名,因此这里是他的示例,以供参考别名“成员”:

    const results = await getRepository(Members)
        .createQueryBuilder("member") // you shall assign an alias
        .where(":id = ANY(member.skill_id_array)", { id: 1 }) // and use that alias everywhere in your query builder
        .getMany();
    

    那么 IN 呢?

    问题是您不能像使用 ANY 那样使用带有 IN 的变量。它永远不会起作用。它需要一个“标量列表”而不是表达式是文档的说法。我的 var 包含一个标量列表,但 IN 参数必须有一个列表,而不是对列表的引用。

    IN (id1, id2, id5) 应该可以工作,您需要在其他地方使用整数或字符串填充这些变量。对于我的应用程序,这意味着解析我的 Skill_id_array 并将各个整数分配给他们自己的唯一变量。当任何人都可以轻松完成相同的结果时,这是一项大量工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-06
      • 2021-04-28
      • 1970-01-01
      • 2020-03-15
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多