12/08/2018, 13:03
Sử dụng MongoDB với gem MongoID phần III
Mongoid(tiếp) Eager Loading Mongoid cung cấp một cơ sở để eager load documents từ các mối quan hệ để ngăn chặn các trường hợp n + 1 khi lặp lại quuery với các mối quan hệ. Eager load được hỗ trợ trên tất cả các mối quan hệ với các trường hợp ngoại lệ belongs_to associations. class ...
- Mongoid(tiếp)
- Eager Loading
Mongoid cung cấp một cơ sở để eager load documents từ các mối quan hệ để ngăn chặn các trường hợp n + 1 khi lặp lại quuery với các mối quan hệ. Eager load được hỗ trợ trên tất cả các mối quan hệ với các trường hợp ngoại lệ belongs_to associations.
class User include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :first_name, type: String field :last_name, type: String field :age, type: Integer, default: 18 field :address, type: String has_many :books end
class Book include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :name, type: String field :author, type: String field :description, type: String field :uesr_id, type: Integer belongs_to :user end
[1] pry(main)> User.includes(:books).each do |user| [1] pry(main)* p user.books.first.name [1] pry(main)* end MOPED: 127.0.0.1:27017 QUERY database=test_development collection=users selector={"deleted_at"=>nil} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.8939ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"deleted_at"=>nil, "user_id"=>{"$in"=>[<BSON::ObjectId:0x34726100 data=5653bead667261191d000000>, <BSON::ObjectId:0x34673880 data=5653bf156672611948000000>, <BSON::ObjectId:0x34671520 data=5653bf186672611948000001>, <BSON::ObjectId:0x34668580 data=5653bf186672611948000002>, <BSON::ObjectId:0x34657020 data=5653bf1c6672611948000003>]}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 1.0358ms "Dolorem quod libero possimus ut dolore." "Est id porro incidunt quod consequatur illo." "Quia debitis qui quis fugit omnis ipsa distinctio." "Odio nemo ab vero dolores neque in rerum quisquam." "Iusto dolores enim aut aperiam tenetur sint." => #<Mongoid::Contextual::Mongo:0x00000004240910 @cache=nil, @cache_loaded=true, @collection= #<Moped::Collection:0x0000000423f650 @database= #<Moped::Database:0x0000000423f6a0 @name="test_development", @session=<Moped::Session seeds=[<Moped::Node resolved_address="127.0.0.1:27017">] database=test_development>>, @name="users">, @criteria=#<Mongoid::Criteria selector: {"deleted_at"=>nil} options: {} class: User embedded: false> , @eager_loaded=true, @klass=User, @query= #<Moped::Query:0x0000000423f510 @collection= #<Moped::Collection:0x0000000423f650 @database= #<Moped::Database:0x0000000423f6a0 @name="test_development", @session=<Moped::Session seeds=[<Moped::Node resolved_address="127.0.0.1:27017">] database=test_development>>, @name="users">, @operation= #<Moped::Protocol::Query @length=0 @request_id=0 @response_to=0 @op_code=2004 @flags=[] @full_collection_name="test_development.tests" @skip=0 @limit=0 @selector={"deleted_at"=>nil} @fields=nil>, @selector={"deleted_at"=>nil}>>
- Queries + Persistence
Mongoid hỗ trợ hiệu qủa bền vững khi bạn muốn thực hiện insert document, update, và delete.- Criteria#create Tạo mới document
[4] pry(main)> User.where(first_name: "Test").create MOPED: 127.0.0.1:27017 INSERT database=test_development collection=users documents=[{"_id"=><BSON::ObjectId:0x12432120 data=5653c34866726119ab000001>, "age"=>18, "deleted_at"=>nil, "first_name"=>"Test", "updated_at"=>2015-11-24 01:54:16 UTC, "created_at"=>2015-11-24 01:54:16 UTC}] flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.9733ms => #<User _id: 5653c34866726119ab000001, created_at: 2015-11-24 01:54:16 UTC, updated_at: 2015-11-24 01:54:16 UTC, deleted_at: nil, first_name: "Test", last_name: nil, age: 18, address: nil>
+ `Criteria#create!` Tạo mới document và trả ra lỗi nếu validation là failure
[6] pry(main)> User.where(first_name: "Test").create! Mongoid::Errors::Validations: Problem: Validation of User failed. Summary: The following errors were found: Last name can't be blank Resolutuby Try persisting the document with valid data or remove the validations. from /home/likewise-open/FRAMGIA/bui.van.quynh/.rvm/gems/ruby-2.2.1/gems/mongoid-4.0.2/lib/mongoid/persistable.rb:78:in `fail_due_to_validation!
+ `Criteria#build|new` Tạo mới document nhưng không save
[7] pry(main)> User.where(first_name: "Test").new => #<User _id: 5653c6226672611c9c000001, created_at: nil, updated_at: nil, deleted_at: nil, first_name: "Test", last_name: nil, age: 18, address: nil> [8] pry(main)> User.where(first_name: "Test").build => #<User _id: 5653c6266672611c9c000002, created_at: nil, updated_at: nil, deleted_at: nil, first_name: "Test", last_name: nil, age: 18, address: nil>
+ `Criteria#update` Update attributes của đối tượng đầu tiên matching
[9] pry(main)> User.where(first_name: "Test").update last_name: "Last Name" MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 1.4813ms MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$set"=>{"last_name"=>"Last Name"}} flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.9015ms => {"connectionId"=>48, "updatedExisting"=>true, "n"=>1, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#update_all` Update attributes tất cả đối tượng matching
[12] pry(main)> User.where(first_name: "Test").update_all last_name: "Last Name" MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$set"=>{"last_name"=>"Last Name"}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.7618ms => {"connectionId"=>48, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#add_to_set`: Thực hiện `$addToSet` tất cả documents matching (attributes là dạng array)
[1] pry(main)> User.where(first_name: "Test").add_to_set address: "Address" MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$addToSet"=>{"address"=>"Address"}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.8743ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#pop`: Thực hiện `$pop` với tất cả document matching(chỉ dùng với adtributes kiểu array)
[4] pry(main)> User.where(first_name: "Test").pop address: "Address Test" MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$pop"=>{"address"=>"Address Test"}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 1.0798ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#pull`: Thực hiện `$pull` với tất cả document matching
[5] pry(main)> User.where(first_name: "Test").pull address: "Address Test" MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.6608ms MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$pull"=>{"address"=>"Address Test"}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.5487ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#pull_all`: Thực hiện `$pullAll` tất cả document matching
[33] pry(main)> User.where(first_name: "Test").pull_all(address: ["Address", "Address Test"]) MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$pullAll"=>{"address"=>["Address", "Address Test"]}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 1.2285ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#push`: Thực hiện `$push` tất cả document matching
[30] pry(main)> User.where(first_name: "Test").push(address: "Adress") MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$push"=>{"address"=>"Adress"}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 1.2555ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#push_all`: Thực hiện `$pushAll` với tất cả documents matching
[32] pry(main)> User.where(first_name: "Test").push_all(address: ["Adress", "test"]) MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.5647ms MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$pushAll"=>{"address"=>["Adress", "test"]}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.5213ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#rename`: Thực hiện `$rename` với tất cả documents matching
[37] pry(main)> User.where(first_name: "Test").rename(first_name: :name) MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.3173ms MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$rename"=>{"first_name"=>"name"}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.3785ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>2, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#set`: Thực hiện `$set` với tất cả document matching
[37] pry(main)> User.where(first_name: "Test").set(age: 20) MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.7750ms MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$set"=>{"age"=>20}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.5255ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>3, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#unset`: Thực hiện `$unset` với tất cả documents matching
[38] pry(main)> User.where(first_name: "Test").unset(:age) MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=users selector={"deleted_at"=>nil, "first_name"=>"Test"} update={"$unset"=>{"age"=>true}} flags=[:multi] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 1.1009ms => {"connectionId"=>53, "updatedExisting"=>true, "n"=>3, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
+ `Criteria#delete`: Thực hiện delete tất cả documents matching
[39] pry(main)> User.where(first_name: "Test").delete MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"users", :query=>{"deleted_at"=>nil, "first_name"=>"Test"}} runtime: 0.3828ms MOPED: 127.0.0.1:27017 DELETE database=test_development collection=tests selector={"deleted_at"=>nil, "first_name"=>"Test"} flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.3049ms => 3
+ `Criteria#destroy`: Xóa tất cả documents phù hợp trong cơ sở dữ liệu trong khi chạy callbacks cho tất cả. Điều này tải tất cả tài liệu vào bộ nhớ và có thể là một hoạt động tốn kém.
[40] pry(main)> User.where(first_name: "Test").destroy MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.3382ms MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"users", :query=>{"deleted_at"=>nil, "first_name"=>"Test"}} runtime: 0.3359ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=tests selector={"deleted_at"=>nil, "first_name"=>"Test"} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.1932ms => 2
- Scoping
- Scope cung cấp 1 cách thuận tiện để tái sử dụng cú pháp ở nhiều nơi
- Named Scopes: Named Scopes là tiêu chí quy định tại lớp được tham chiếu bởi một tên đã cung cấp.
- Scope cung cấp 1 cách thuận tiện để tái sử dụng cú pháp ở nhiều nơi
class Book include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :name, type: String field :author, type: String field :description, type: String field :uesr_id, type: Integer field :country, type: String belongs_to :test scope :english_books, ->{where country: "en"} end
[16] pry(main)> Book.english_books => #<Mongoid::Criteria selector: {"deleted_at"=>nil, "country"=>"en"} options: {} class: Book embedded: false> [17] pry(main)> Book.english_books.count MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"books", :query=>{"deleted_at"=>nil, "country"=>"en"}} runtime: 1.1498ms => 12
+ `Named scopes` có thể mở rộng thêm các tham số và có thể nằm trong blocks hoặc mở rộng chức năng
class Book include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :name, type: String field :author, type: String field :description, type: String field :uesr_id, type: Integer field :country, type: String belongs_to :test scope :english_books, ->{where country: "en"} scope :by_country, ->country {where country: country} scope :jp_books, -> do where country: "jp" end end
[1] pry(main)> Book.by_country("en") => #<Mongoid::Criteria selector: {"deleted_at"=>nil, "country"=>"jp"} options: {} class: Book embedded: false> [2] pry(main)> Book.by_country("en").count MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"books", :query=>{"deleted_at"=>nil, "country"=>"jp"}} runtime: 1.7488ms => 12 [3] pry(main)> Book.jp_books => #<Mongoid::Criteria selector: {"deleted_at"=>nil, "country"=>"jp"} options: {} class: Book embedded: false> [4] pry(main)> Book.jp_books.count MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"books", :query=>{"deleted_at"=>nil, "country"=>"jp"}} runtime: 0.9492ms => 12
+ Default Scopes `Default scopes `có thể hữu ích khi bạn thấy mình áp dụng cùng một tiêu chuẩn cho hầu hết các truy vấn.
class Book include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :name, type: String field :author, type: String field :description, type: String field :uesr_id, type: Integer field :country, type: String belongs_to :test scope :english_books, ->{where country: "en"} scope :by_country, ->country {where country: country} scope :jp_books, -> do where country: "jp" end default_scope ->{order_by(:created_at.desc)} end
[4] pry(main)> Book.jp_books => #<Mongoid::Criteria selector: {"deleted_at"=>nil, "country"=>"jp"} options: {:sort=>{"created_at"=>-1}} class: Book embedded: false>
+ Bạn có thể nói với Mongoid không áp dụng `default_scope` bằng cách sử dụng `unscoped` có thể trong 1 dòng hoặc 1 khối.
[5] pry(main)> Book.unscoped.jp_books => #<Mongoid::Criteria selector: {"country"=>"jp"} options: {} class: Book embedded: false>
+ Bạn có thể nói với Mongoid 1 cách rõ ràng khi nào sử dụng `default_scope` bằng cách sử dụng `scoped`
[6] pry(main)> Book.unscoped.jp_books.scoped => #<Mongoid::Criteria selector: {"country"=>"jp", "deleted_at"=>nil} options: {:sort=>{"created_at"=>-1}} class: Book embedded: false>
+ Class Methods `Class Method` trên `models` trả về các đối tượng , nó cũng được coi như `scoped` và có thể ràng buộc tốt.
class Book include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :name, type: String field :author, type: String field :description, type: String field :uesr_id, type: Integer field :country, type: String belongs_to :test scope :english_books, ->{where country: "en"} scope :by_country, ->country {where country: country} scope :jp_books, -> do where country: "en" end default_scope ->{order_by(:created_at.desc)} class << self def us_books where country: "us" end end end
[2] pry(main)> Book.us_books => #<Mongoid::Criteria selector: {"deleted_at"=>nil, "country"=>"us"} options: {:sort=>{"created_at"=>-1}} class: Book embedded: false>
+ Map/Reduce Mongoid cung cấp một DSL xung quanh MongoDB’s map/reduce framework, để thực hiện các công việc map/reduce hoặc tập hợp đơn giản. + Execution: Bạn có thể khai báo `Mongoid` ra khỏi `class` hoặc một tiêu chí để thực hiện một `map/reduce` bằng cách gọi `map_reduce` và cung cấp `map` và `reduce` cho javascript functions.
-
Relation
- Common Behaviour + Attributes: Tất cả relations đều chứa target, đó là những proxied document or documents, base là document của relation nguồn.
class Test include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia include Mongoid::Attributes::Dynamic field :first_name, type: String field :last_name, type: String field :age, type: Integer, default: 18 field :address, type: Array validates :last_name, presence: true has_many :books end
[9] pry(main)> User.first.books MOPED: 127.0.0.1:27017 QUERY database=test_development collection=users selector={"$query"=>{"deleted_at"=>nil}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 1.1196ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "user_id"=><BSON::ObjectId:0x52474000 data=5653bead667261191d000000>}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.8906ms =>[#<Book _id: 5653bf636672611948000004, created_at: 2015-11-24 01:37:39 UTC, updated_at: 2015-11-24 01:37:39 UTC, deleted_at: nil, name: "Consectetur nulla autem natus voluptatem saepe eum quia.", author: "Mrs. Hettie Jenkins", description: "Est iste aperiam blanditiis quod dolorum sint ullam.", country: nil, user_id: <BSON::ObjectId:0x52345920 data=5653bead667261191d000000>>ư [10] pry(main)> User.first.books.target MOPED: 127.0.0.1:27017 QUERY database=test_development collection=users selector={"$query"=>{"deleted_at"=>nil}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.4310ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "user_id"=><BSON::ObjectId:0x51830620 data=5653bead667261191d000000>}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.9328ms => [#<Book _id: 5653bf636672611948000004, created_at: 2015-11-24 01:37:39 UTC, updated_at: 2015-11-24 01:37:39 UTC, deleted_at: nil, name: "Consectetur nulla autem natus voluptatem saepe eum quia.", author: "Mrs. Hettie Jenkins", description: "Est iste aperiam blanditiis quod dolorum sint ullam.", country: nil, user_id: <BSON::ObjectId:0x51775860 data=5653bead667261191d000000>>] [11] pry(main)> User.first.books.base MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.7714ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=users selector={"$query"=>{"deleted_at"=>nil}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 1.1108ms => #<User _id: 5653bead667261191d000000, created_at: 2015-11-24 01:34:37 UTC, updated_at: 2015-11-24 01:34:37 UTC, deleted_at: nil, first_name: "Alfredo", last_name: "Keebler", age: 18, address: "67756 Reba Place">