Rails+PostgreSQL JSONB(섹션 1)

34402 단어 railspostgres
Rails+PostgreSQL JSONB 시리즈
섹션 1: 마이그레이션 및 때
만약 이 글을 계속 읽는다면, 나는 당신이 Ruby, Ruby의 OOP, RoR,Active Record를 이해한다고 가정합니다.
이 화제에 관한 문장은 많지 않다.기존 약관이라도 자세한 설명은 없다.나는 많은 문장을 읽어야만 잘 표현할 수 있다.
이것은 내가 처음으로 한 화제를 깊이 있게 탐구한 것이다.
Rails>=4.2, PostgreSQL>=9.4 필요

PostgreSQL has JSON and JSONB column type. They are look the same, but there are many differences, especially in functionality. I recommend to use JSONB instead of JSON, as JSONB column type is the upgraded version of JSON.


JSONB 열 유형을 사용하는 이유는 무엇입니까?

The advantage of using jsonb is that you can easily integrate relational and non-relation data, with performance that can be better than most non-relational databases like MongoDB.

source: this article


우리의 여정을 시작합시다!(나는 단지 Rails API를 예로 들었을 뿐이지만, 본문은 일반 Rails에서도 실현할 수 있다)
디렉토리:
1. Migration
2. Create
3. Show
4. Validation
5. Update
6. Final Word

1. 이민


그것은 다른 열 유형과 마찬가지로 간단하다.
# db/migrate/*_create_books.rb
class CreateBooks < ActiveRecord::Migration[5.2]
  def change
    create_table :books do |t|
      t.integer :user_id
      t.jsonb :payload, null: false, default: '{}'
    end
  add_index :books, :payload, using: :gin
  end
end
참고:
우선, 당신은 사용할 필요가 없습니다 null: false, default: '{}'. 그러나, 나는 당신이 그것을 사용하는 것을 건의합니다.단지 네가 그것이 맞는지 검사할 필요가 없기 때문이다nil.
# if you allow nil OR dont't state default value to a hash
Book.create(user_id: 1)
Book.last.payload['title']
# => NoMethodError (undefined method `[]' for nil:NilClass)

# if you don't allow nil AND state default value to a hash
Book.create(user_id: 1)
Book.last.payload['title']
# => nil
그 다음으로 GIN 색인도 정의했습니다.나는 두 번째 부분에서 이 점을 소개할 것이다.
셋째, 나는 열 이름을 payload 로 명명하지만, 루비, rails,postgresql가 허락하면 마음대로 명명할 수 있습니다.

창조


레코드 작성도 간단합니다.
book_payload = {
  title: 'Hacking Growth',
  publisher: 'Currency',
  published_date: '2017-04-07',
  authors: [
    {
      id: 1,
      name: 'Sean Ellis'
    },
    {
      id: 2,
      name: 'Morgan Brown'
    }
  ]
}

Book.create(user_id: 1, payload: book_payload)
됐다!

3. 공연


디스플레이 데이터는 매우 간단하다.JSONB로 정의된 모든 열은 해시로 표시되며 모든 키는 문자열로 반환됩니다.
Book.last.user_id
# => 1

Book.last.payload['title']
# => "Hacking Growth"

Book.last.payload['authors'][0]['name']
# => "Sean Ellis"
또한 기호를 사용하여 JSON 객체에 액세스할 수 있도록 시리얼화된 프로그램을 사용자화하려면 다음과 같이 하십시오.
# app/models/book.rb
class Book < ApplicationRecord
  belongs_to :user
  serialize :payload, JsonbSerializers
end

# app/serializers/jsonb_serializers.rb
class JsonbSerializers
  def self.dump(hash)
    hash.to_json
  end

  def self.load(hash)
    (hash || {}).with_indifferent_access
  end
end
Book.last.payload[:title]
# => "Hacking Growth"

4. 검증


JSOB 열 유형의 문제는 검증을 하지 않으면 무모드가 된다는 것이다.이 열에 모든 모드를 입력할 수 있습니다.다음 코드를 확인하십시오.
book_payload = {
  title: 'Getting to Plan B',
  pubs: 'Harvard Business Review Press',
  authors: 'John W Mullins'
  rating: 3.5
}

Book.create(user_id: 1, payload: book_payload)
위의 레코드는 DB 형식으로 제출됩니다.대다수 상황에서 이것은 큰 문제다.
API 사용자가 제공한 매개 변수가 정확한지 오류인지 어떻게 검증합니까?우리는 반드시 두 가지 절차를 해야 한다.
  • JSON 모드 사용
  • 화이트리스트 매개 변수
  • 첫 번째 단계는 JSON 모드를 사용합니다.나는 JSON 모드가 무엇인지 소개하지 않을 것이다.공식 페이지here는 완벽하고 이해할 수 있습니다.
    Rails에서 JSON 모드를 어떻게 사용합니까?우리는 보석을 사용하고 있다.보석은 적지만 내가 유일하게 사용한 것은activerecord_json_validator gems이다.(이gem은 JSON 모드의 초안-04만 제공됨)Book 모델에 대한 JSON 모드를 생성합니다.우리는 패턴을 우리가 원하는 곳에 놓을 수 있지만, 나는 그것들을 app/models/schemas에 놓는 것을 좋아한다.
    JSON 모드를 이해하려면 thisthis를 사용할 수 있습니다.이 두 개면 충분하다.
    // app/models/schemas/book_payload.json
    {
      "$schema": "http://json-schema.org/draft-04/schema",
      "type": "object",
      "required": [ "title", "publisher", "published_date", "authors" ],
      "properties": {
        "title": { "type": "string" },
        "publisher": { "type": "string" },
        "published_date": { "type": "string" },
        "authors": {
          "type": "array",
          "items": {
            "$ref": "authors.json#/definitions/data"
          },
          "minItems": 1,
          "uniqueItems": true
        }
      }
    }
    
    // app/models/schemas/authors.json
    {
      "definitions": {
        "data": {
          "type": "object",
          "required": [ "id", "name" ],
          "properties": {
            "id": { "type": "integer" },
            "name": { "type": "string" }
          }
        }
      }
    }
    
    그런 다음 Gemfile에 넣고 번들로 설치합니다.
    gem 'activerecord_json_validator'
    
    그리고 우리는 우리의 모형을 갱신한다.(이 보석을 이해하려면 그들의 github page만으로도 충분하다.)
    # app/models/book.rb
    class Book < ApplicationRecord
      ...
    
      PAYLOAD_SCHEMA = "#{Rails.root}/app/models/schemas/book_payload.json"
      validates :payload, presence: true, json: { message -> (err) { err }, schema: PAYLOAD_SCHEMA }
    end
    
    첫 번째 단계는 완성이다.이제 다음 코드를 보십시오.
    book_payload = {
      title: 'Getting to Plan B',
      pubs: 'Harvard Business Review Press',
      authors: 'John W Mullins'
      rating: 3.5
    }
    
    Book.create!(user_id: 1, payload: book_payload)
    
    위의 코드는 json이 잘못되었기 때문에 검증 오류를 던질 것입니다.없음publisherparam, 없음publisher_dateparam, 그리고 authorsparam은 그룹이 아닙니다.
    다음 코드를 살펴보십시오.
    book_payload = {
      title: 'Getting to Plan B',
      publisher: 'Harvard Business Review Press',
      published_date: '2009-09-08',
      pubs: 'Harvard Business Review Press',
      authors: [
        {
          id: 3,
          name: 'John W Mullins',
          web: 'http://www.johnwmullins.com'
        }
      ],
      rating: 4.2
    }
    
    Book.create!(user_id: 1, payload: book_payload)
    
    위의 코드는 검증 오류를 일으키지 않습니다!왜냐하면 그것은 효과적인 json이기 때문이다.너도 pubs하고 rating!
    Book.last.payload['pubs']
    # => "Harvard Business Review Press"
    
    Book.last.payload['rating']
    # => 4.2
    
    Book.last.payload['authors'][0]['web']
    # => "http://www.johnwmullins.com"
    
    만약 API 소비자가 모든 요청에 100개의 파라미터를 제공한다면, 당신의 데이터 저장소는 당신이 영원히 필요로 하지 않는 쓰레기를 처리하는 데 사용될 것입니다.
    이것이 바로 우리가 화이트리스트 파라미터를 필요로 하는 이유다.
    두 번째 단계는 컨트롤러에서 백명단 파라미터를 표시합니다.이것은 JSONB 열 유형뿐만 아니라 다른 열 유형에도 필요합니다.
    디렉터를 업데이트합니다.
    # app/controllers/books_controller.rb
    class BooksController < ApplicationController
      def create
        book = Book.create!(book_params)
        render json: { status: "OK", message: "Book created!", object: book }, status: 201
      end
    
      private
    
      def book_params
        params.permit(
          payload: [
            :title,
            :publisher,
            :published_date,
            authors: [
              :id,
              :name
            ]
          ]
        )
      end
    end
    
    너는 화이트리스트 파라미터가 어떻게 작동하는지 안다.나는 위의 코드를 설명할 필요가 없다고 생각한다.
    이렇게현재, jsonb열을 검증했습니다.

    5. 업데이트


    Note: All of the examples in this chapter are assuming you don't have validation for payload column in Book.


    JSONB 열을 업데이트하는 것은 좀 까다롭다.만약 네가 이 책의 마지막 기록의 제목만 바꾸고 싶다면.하면, 만약, 만약...
    Book.last.payload
    # => {"title"=>"Hacking Growth", "publisher"=>"Currency", "published_date"=>"2017-04-07", "authors"=>[{"id"=>1, "name"=>"Sean Ellis"}, {"id"=>2, "name"=>"Morgan Brown"}]}
    
    book_payload = {
      title: 'Blue Ocean'
    }
    
    Book.last.update(payload: book_payload)
    
    지금 너의 payloadtitle만 포함된다!
    Book.last.payload
    # => {"title"=>"Blue Ocean"}
    
    Book.last.payload['publisher']
    # => nil
    
    Book.last.payload['authors']
    # => nil
    
    올바른 방법:
    book = Book.last
    book.payload['title'] = 'Blue Ocean'
    book.save!
    
    Book.last.payload
    # => {"title"=>"Blue Ocean", "publisher"=>"Currency", "published_date"=>"2017-04-07", "authors"=>[{"id"=>1, "name"=>"Sean Ellis"}, {"id"=>2, "name"=>"Morgan Brown"}]}
    
    JSONB 열에 대한 프롬프트를 업데이트하려면 다음과 같이 하십시오.
    # app/controllers/books_controller.rb
    class BooksController < ApplicationController
      def update
        UpdateBookPayload.new(update_params).call
        render json: { status: "OK", message: "Book updated!" }, status: 200
      end
    
      private
    
      def update_params
        params.permit(
          :book_id,
          :title,
          :publisher,
          :published_date,
          authors: [
            :id,
            :name
          ]
        )
      end
    end
    
    # app/lib/update_book_payload.rb
    class UpdateBookPayload
      def initialize(params)
        @params = params
        @book   = book
      end
    
      def call
        iterate_params
        @book.save!
      end
    
      private
    
      def book
        Book.find(@params[:book_id])
      end
    
      def iterate_params
        params = @params.delete('book_id')
        params.each do |key1, value1|
          if key1 == 'authors'
            iterate_authors(key1, value1)
          else
            @book.payload[key1] = (value1 || @book.payload[key1])
          end
        end
      end
    
      def iterate_authors(key1, value1)
        value1.each_with_index do |value2, key2|
          value2.each do |key3, value3|
            @book.payload[key1][key2][key3] = (value3 || @book.payload[key1][key2][key3])
          end
        end
      end
    end
    
    따라서 API 사용자는 모든 json을 사용자에게 전달할 수 있습니다.rails 콘솔을 사용하여 perform에서 클래스를 확인할 수 있습니다.
    Book.last.id
    # => 10
    
    Book.last.payload
    # => {"title"=>"Hacking Growth", "publisher"=>"Currency", "published_date"=>"2017-04-07", "authors"=>[{"id"=>1, "name"=>"Sean Ellis"}, {"id"=>2, "name"=>"Morgan Brown"}]}
    
    params = {
      book_id: 10,
      title: 'Blue Ocean',
      authors: [
        {},
        { id: 5 }
      ]
    }
    
    UpdateBookPayload.new(params).call
    
    Book.last.payload
    # => {"title"=>"Blue Ocean", "publisher"=>"Currency", "published_date"=>"2017-04-07", "authors"=>[{"id"=>1, "name"=>"Sean Ellis"}, {"id"=>5, "name"=>"Morgan Brown"}]}
    

    6. 마지막 한마디


    이것은 첫 번째 부분의 결말이다.제2부분에서 저는 store_accessor, 조회와 인덱스를 소개할 것입니다.
    자료 출처: 나 자신과 많은 자료의 발췌문, 나는 그것들을 보존하지 않는다. 나는 내가 기억하는 것만 쓴다.

    좋은 웹페이지 즐겨찾기