TypeORM Postgres WHERE ANY 或 IN QueryBuilder 或 Find?

Pre*_*ton 7 typeorm

我一直在试图弄清楚如何在具有整数数组的列中选择包含特定 id 的 Postgres 数据库中的每条记录。我是新手,但我相信我想要一个看起来像这样的 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。由此产生的错误在评论中。(完整的 CRUD 正在运行,所以我的整体设置很好。)

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

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

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

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

在我的服务中:

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;
  }
Run Code Online (Sandbox Code Playgroud)

实体:

  @Column('int', { array: true, nullable: true})
  skill_id_array: number[];
Run Code Online (Sandbox Code Playgroud)

Postgres 列类型: integer[]

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

小智 24

如果你使用面向对象编程

const list = await this.repository.find({ where: { id: In([...idArr]) } });
Run Code Online (Sandbox Code Playgroud)


Tre*_*Gun 19

目前可以使用语法

.where("id IN(:...ids)", { ids: [1,2,3] })
Run Code Online (Sandbox Code Playgroud)

  • 问题是变量的使用,而不是硬编码数组。我已经解决了这个问题。我看到你是新人,但否则我会否决你的答案。在尝试回答之前,请务必先理解问题和其他答案。祝你一切顺利。 (2认同)
  • 这将使用 QueryBuilder 工作,但不能使用原始 sql 查询的查询方法 (2认同)
  • 您可以在这里找到有关此语法的讨论:https://github.com/typeorm/typeorm/issues/1239 (2认同)

Pre*_*ton 6

网上很多地方都说 SQL 操作符 IN 和 ANY 几乎是等价的。所以我认为它们的设置几乎相同,只是 ANY 需要“=”。错了,但花了很长时间才弄明白。

QueryBuilder 中的 ANY 设置有效:

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

以前我使用 TypeORM Find Options 文档中的“Any”设置,因为 ANY 尚未在 QueryBuilder 文档中解决。这似乎是当时要走的路,但不要将它们混在一起。

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();
Run Code Online (Sandbox Code Playgroud)

那么IN呢?

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

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