如何执行 TypeORM 的模糊查询

72

大家好,我正在尝试查找所有包含 a 的结果。我尝试了几种方法,但问题是没有一种方法有效。它只返回一个空数组。

你好,我正在尝试查找所有具有“a”的结果。我尝试了几种方法,但问题是没有一种方法有效。它只返回一个空数组。

var data = await getRepository(User)
  .createQueryBuilder("user")
  .where("user.firstName = %:name%", { name: firstName })
  .getMany();

以及类似这样的内容

var data = await getRepository(User)
  .createQueryBuilder("user")
  .where("user.firstName like %:name%", { name: firstName })
  .getMany();

但是什么都不起作用。所有这些都返回一个空数组。有人可以帮助我吗,谢谢。

7个回答

145

正确的方式是:

 var data = await getRepository(User)
                  .createQueryBuilder("user")
                  .where("user.firstName like :name", { name:`%${firstName}%` })
                  .getMany();

3
这个问题是在询问是否能正确地转义 firstName - user3413723
1
我测试过了...我认为它对参数进行了处理。 - user3413723
1
@user3413723 我刚测试了一下。它确实转义了引号和其他字符,但它无法转义“%”和“_”字符(也不应该这样做)。 - david_p
7
SQL注入攻击! - Siyavash Hamdi
这个有官方文档吗?我找不到。 - Siva Sankaran

113

TypeORM 提供了开箱即用的 Like 函数。例如从他们的文档中:Advanced Options

import {Like} from "typeorm";

const loadedPosts = await connection.getRepository(Post).find({
    title: Like("%out #%")
});

在您的情况下:

var data = await getRepository(User).find({
    name: Like(`%${firstName}%`)
});

4
如果你像我一样想要使用ilike,看起来它将会在即将发布的版本中加入:https://github.com/typeorm/typeorm/pull/5828 - Aaron
11
如果firstName的值不安全,那么你的解决方案就无法防止SQL注入攻击。 - LucaRoverelli
2
@LucaRoverelli,如何使它免受SQL注入攻击?使用相同的语法是否可能? - forJ
1
无法在MongoDB上工作 - Muhammad Awais
1
@LucaRoverelli 我认为这个解决方案受到了SQL注入的保护,因为我们没有构建原始查询。值将作为参数化注入到SQL查询中。我们可以通过启用数据源中的日志选项来检查底层查询。 - pathe.kiran

8
你可以使用数据库函数进行连接。例如,在Postgres中:

您还可以使用数据库功能来进行连接。在postgres中:

 var data = await getRepository(User)
              .createQueryBuilder("user")
              .where("user.firstName like '%' || :name || '%'", {name: firstName })
              .getMany();

7

目前为止所有答案,包括pleerock的被采纳的答案,似乎都容易受到SQL注入攻击,除非用户输入已经事先进行了净化处理。

 var data = await getRepository(User)
              .createQueryBuilder("user")
              .where("user.firstName like :name", { name:`%${firstName}%`})
              .getMany();

上面的代码在TypeORM中是有效的,这意味着任何类似的查询都容易受到数据外泄的攻击。设想以下类似的查询:
 const data = await getRepository(User)
          .createQueryBuilder("user")
          .where("user.firstName like :name", { name: firstName })
          .getOne();

用户输入未经过处理的数据中包含字符%,并被发送到上述查询的firstName中(例如let firstName = '%John'),这将允许用户窃取其他用户的潜在私密数据。

因此,在使用情况允许的情况下,应该确保对任何用户输入进行清理,删除任何特殊字符。

或者,在MySQL中,如果需要文本中存在特殊字符,则使用全文搜索可能更合适。但是,这种做法的维护成本更高。

在相关列上创建全文搜索,然后执行查询。

    export class User {
        @PrimaryGeneratedColumn()
        id: number;

        @Index({fulltext: true})
        @Column()
        name: string;
    }

    const data = await this.repository
         .createQueryBuilder()
         .select()
         .where('MATCH(name) AGAINST (:name IN BOOLEAN MODE)', {name: name})
         .getOne()

1
var data = await  getRepository(User)
                        .createQueryBuilder("user")
                        .where("user.firstName ILIKE %q", {q:`%${VALUE_HERE}%` })
                .getMany();

这是我做的方式。希望能有所帮助。

这个存在 SQL 注入漏洞。 - tanner burton
@tannerburton 为什么?即使被%包围,TypeORM也不会对参数进行清理吗? - Petruza

1

"typeorm": "^0.3.5"

使用TyeORM和Mysql可以这样操作

import {Like} from "typeorm";

const loadedPosts = await UserRepository.find({
    where: {
      name: Like("%Mar%")
    }
});

你可以使用这个:

import {Like} from "typeorm";

const filters={
  name: 'Ca',
  age: '3'
}

const columnFilters={}
for(const i in filters){
  columnFilters[i]= Like(`%${filters[i]}%`)
}

const loadedPosts = await UserRepository.find({
    where: columnFilters
});

-2
使用存储库,我将其放在“where”子句中,例如:
let res = await this.trackingRepository.findAndCount({
      where: [{ username : Like(`%${searchValue}%`) },
              { action : Like(`%${searchValue}%`) },
              { ip : Like(`%${searchValue}%`) }],
      order: {
        [sortField]: sortOrder === "descend" ? 'DESC' : 'ASC',
      },
      skip: (current - 1) * pageSize,
      take: pageSize,
    });

6
不应手动插入数值,你的代码容易受到 SQL 注入攻击。 - gogeccc
最好的替换方法是什么? - Salah ED
1
使用查询参数。我会更新您的答案以使用查询参数。 - gogeccc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接