【问题标题】:How to query JSONB field with IN operator in rails - active record如何在 Rails 中使用 IN 运算符查询 JSONB 字段 - 活动记录
【发布时间】:2021-11-18 20:55:09
【问题描述】:

我有一个名为 lms_data 的 jsonb 列,其中包含一个哈希数据结构。我正在尝试查找与 id 数组匹配的元素。此查询有效并返回正确的结果:

CoursesProgram
.joins(:course)
.where(program_id: 12)
.where(
"courses.lms_data->>'_id' IN ('604d26cadb238f542f2fa', '604541eb0ff9d7b28828c')")

SQL 日志:

  CoursesProgram Load (0.5ms)  SELECT "courses_programs".* FROM "courses_programs" INNER JOIN "courses" ON "courses"."id" = "courses_programs"."course_id" WHERE "courses_programs"."program_id" = $1 AND (courses.lms_data->>'_id' IN ('604d26cadb61e238f542f2fa', '604541eb0ff9d8387b28828c'))  [["program_id", 12]

但是,当我尝试将变量作为 id 数组传递时:

CoursesProgram
.joins(:course)
.where(program_id: 12)
.where(
  "courses.lms_data->'_id' IN (?)",
["604d26cadb61e238f542f2fa", "604541eb0ff9d8387b28828c"])

我没有得到任何结果,并且在日志中执行了两个查询...

 CoursesProgram Load (16.6ms)  SELECT "courses_programs".* FROM "courses_programs" INNER JOIN "courses" ON "courses"."id" = "courses_programs"."course_id" WHERE "courses_programs"."program_id" = $1 AND (courses.lms_data->'_id' IN ('604d26cadb61e238f542f2fa','604541eb0ff9d8387b28828c'))  [["program_id", 12]]
  CoursesProgram Load (0.8ms)  SELECT "courses_programs".* FROM "courses_programs" INNER JOIN "courses" ON "courses"."id" = "courses_programs"."course_id" WHERE "courses_programs"."program_id" = $1 AND (courses.lms_data->'_id' IN ('604d26cadb61e238f542f2fa','604541eb0ff9d8387b28828c')) LIMIT $2  [["program_id", 12], ["LIMIT", 11]]

我无法理解这个。 在这两种情况下执行的查询似乎是相同的。为什么一个工作而另一个不工作?为什么在第二种情况下查询会执行两次?

【问题讨论】:

    标签: ruby-on-rails postgresql activerecord jsonb


    【解决方案1】:

    问号是postgres的json查询函数集中自己的算子(意思是,这个存在吗)。 ActiveRecord 正在尝试做它认为你想要做的事情,但是期望有局限性。

    解决方案。 不要使用它。自从?可能会导致 postgres 的 json 查询出现问题,我改用命名替换。

    来自postgres documentation:

    ?|  text[]  Do any of these array strings exist as top-level keys?  '{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'c']
    

    所以首先我们使用?| postgres json 运算符在 lms_data 的值中查找 ANY。

    其次,我们告诉 postgres 我们将使用一个带有 postgres 数组函数 array[:named_substitution] 的数组

    最后,在 postgres 查询末尾的 , 之后,添加您的命名子变量(在本例中我使用 :ids)和您的数组。

    CoursesProgram
      .joins(:course)
      .where(program_id: 12)
      .where(
        "courses.lms_data->>'_id' ?| array[:ids]", 
        ids: ['604d26cadb238f542f2fa', '604541eb0ff9d7b28828c'])
    

    【讨论】:

    • 也许我的问题没有很好地表述,因为我没有尝试在 lms_data jsonb 字段中找到与我的 id 数组匹配的键。相反,我试图找到具有与数组中的值之一匹配的 lms_data -> _id 的 CourseProgram 的所有实例
    • 运行您建议的查询,我仍然得到 2 个不同的查询并且没有结果:``` CoursesProgram Load (3.7ms) SELECT "courses_programs".* FROM "courses_programs" INNER JOIN "courses" ON "课程"."id" = "courses_programs"."course_id" WHERE "courses_programs"."program_id" = $1 AND (courses.lms_data->>'_id' ?| array['604541c85bbec2473a962eeb','603d763a28dc3c2ae051ed2a']) [[ “program_id”,10]]```
    • ``` CoursesProgram Load (0.7ms) SELECT "courses_programs".* FROM "courses_programs" INNER JOIN "courses" ON "courses"."id" = "courses_programs"."course_id" WHERE " course_programs"."program_id" = $1 AND (courses.lms_data->>'_id' ?| array['604541c85bbec2473a962eeb','603d763a28dc3c2ae051ed2a']) 限制 $2 [["program_id", 10], ["LIMIT", 11] ]```
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-26
    相关资源
    最近更新 更多