【问题标题】:nested query on active model serializer attribute对活动模型序列化程序属性的嵌套查询
【发布时间】:2020-10-25 13:41:55
【问题描述】:

我有两个模型,Artwork 和 Event,一个艺术品有很多事件。 部分事件已确认。

在我的序列化程序中,我想返回每个 Artwork 的最后确认事件

现在它会这样做,但也会创建一个缓慢的 (n+1 ?) 查询,其中每个序列化的 Artwork 都会获取所有事件。

我怎样才能更快地做某事?


# artwork_controller.rb
      def index
        @artworks = Artwork.all
        render json: @artworks
      end

# artwork_serializer.rb
      attributes :id, :name, :photo, :created_at

      has_one :event do
        object.events.confirmed.last
      end

和日志

Processing by Api::V1::ArtworksController#index as JSON
  Passenger Load (2.0ms)  SELECT "artworks".* FROM "artworks"
  ↳ app/controllers/api/v1/artworks_controller.rb:11
[active_model_serializers]   Event Load (1.2ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 16], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   Event Load (0.8ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 9], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   Event Load (2.1ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 27], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9#
# ... for each artwork

[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   User Load (1.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 84], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/event_serializer.rb:9
[active_model_serializers]   CACHE Event Load (0.0ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 9], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   User Load (0.6ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 88], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/event_serializer.rb:9
[active_model_serializers]   CACHE Event Load (0.0ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 27], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 76], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/event_serializer.rb:9
[active_model_serializers]   CACHE Event Load (0.0ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 11], ["published", true], ["LIMIT", 1]]
# ... for each artwork events

【问题讨论】:

    标签: ruby-on-rails performance activerecord active-model-serializers


    【解决方案1】:

    你可以试试这个:

    请将此关联添加到artwork 模型。

    # app/models/artwork.rb
    
    has_one :last_confirmed_event, -> { order(created_at: :desc).where(confirmed: true) }, class_name: "Event"
    

    在您的 artworks 控制器中添加急切加载。

    # app/controllers/artwork_controllers.rb
    
    def index 
      @artworks = Artwork.all.includes(:last_confirmed_event)
      render json: @artworks 
    end
    

    在您的序列化程序中最后一次使用声明的关联。

    # app/serializers/artwork_serializer.rb
    
    attributes :id, :name, :photo, :created_at
    
    has_one :last_confirmed_event
    

    您可以根据自己的选择更改关联名称。

    【讨论】:

    • 几乎总是返回第一个事件,而不是最后一个,调整查询就可以了has_one :last_ confirmed_event, -> { order(created_at: :desc).where(confirmed: true) }, class_name: 'Event'
    猜你喜欢
    • 2016-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    相关资源
    最近更新 更多