You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何对JSONField数组的对象属性进行模糊过滤?

问题描述

我在MySQL数据库中有如下结构的记录:

{
    "id": 44207,
    "actors": [
        {
            "id": "9c88bd9c-f41b-59fa-bfb6-427b1755ea64",
            "name": "APT41",
            "scope": "confirmed"
        },
        {
            "id": "6f82bd9c-f31b-59fa-bf26-427b1355ea64",
            "name": "APT67",
            "scope": "confirmed"
        }
    ]
},
{
    "id": 44208,
    "actors": [
        {
            "id": "427b1355ea64-bfb6-59fa-bfb6-427b1755ea64",
            "name": "APT21",
            "scope": "confirmed"
        },
        {
            "id": "9c88bd9c-f31b-59fa-bf26-427b1355ea64",
            "name": "APT22",
            "scope": "confirmed"
        }
    ]
},
...

其中actors是JSONField类型。我需要过滤出所有actors数组中任意对象的name字段包含'67'的记录。

我尝试过以下方法,但均存在局限:

  • 使用queryset.filter(actors__contains=[{"name":"APT67"}]):仅支持精确匹配actor.name的值,无法实现模糊匹配;
  • 使用queryset.filter(actors__0__name__icontains='67'):仅能匹配数组第一个元素符合条件的记录;
  • 借助models.Q构建多个OR条件:
search_query = models.Q(actors__0__name__icontains='67') | models.Q(actors__1__name__icontains='67') | models.Q(actors__2__name__icontains='67') | models.Q(actors__3__name__icontains='67')
queryset.filter(search_query)

这种方式代码冗余,且仅能覆盖有限数量的数组元素。

请问是否存在更规范、通用的解决方法?

通用解决方法

方法1:利用MySQL原生JSON_SEARCH函数(推荐)

MySQL的JSON_SEARCH函数支持在JSON结构中进行模糊搜索,能直接定位数组内任意元素的指定字段是否匹配模糊条件。通过extra()方法嵌入原生SQL条件即可实现:

queryset = YourModel.objects.extra(
    where=["JSON_SEARCH(actors, 'one', '%67%', NULL, '$[*].name') IS NOT NULL"]
)

参数说明:

  • 'one':找到第一个匹配项即停止搜索,提升查询性能;
  • '%67%':模糊匹配模式,对应SQL的LIKE语法;
  • '$[*].name':指定搜索路径为actors数组中所有元素的name字段;
  • 若需不区分大小写匹配,可结合LOWER()函数:
queryset = YourModel.objects.extra(
    where=["JSON_SEARCH(LOWER(actors), 'one', '%67%', NULL, '$[*].name') IS NOT NULL"]
)

方法2:用Django Func表达式封装JSON函数

为了贴合Django ORM的写法,可直接使用Func类封装JSON_SEARCH,避免直接编写原生SQL字符串:

from django.db.models import Func

queryset = YourModel.objects.filter(
    Func(
        'actors', 'one', '%67%', None, '$[*].name',
        function='JSON_SEARCH'
    ).isnull(False)
)

这种方式既保留了ORM的可读性,又能利用MySQL的JSON函数能力。

方法3:JSON_TABLE展开数组(MySQL 8.0+)

如果使用MySQL 8.0及以上版本,JSON_TABLE可以将JSON数组转换为关系型临时表,通过关联查询实现筛选,适合更复杂的数组元素分析场景:

queryset = YourModel.objects.raw("""
    SELECT DISTINCT t.*
    FROM your_model_table t
    JOIN JSON_TABLE(
        t.actors,
        '$[*]' COLUMNS(
            name VARCHAR(255) PATH '$.name'
        )
    ) jt
    WHERE jt.name LIKE '%67%'
""")

注意替换your_model_table为你的实际数据库表名,DISTINCT用于避免因数组多个匹配元素导致的重复记录。


内容的提问来源于stack exchange,提问作者farefray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 06:15:42