12/08/2018, 13:08
Sử Dụng MongoDB Với Gem MongoID Phần IV
Mongoid(tiếp) Relations Common Behaviour Tất cả các quan hệ đều chứa đích đến, đó là những documents được đại diện, hoặc những documents, cơ sở đó là những documents liên kết ra, và các metadata cung cấp thông tin về các quan hệ. class Test include ...
- Mongoid(tiếp)
- Relations
- Common Behaviour Tất cả các quan hệ đều chứa đích đến, đó là những documents được đại diện, hoặc những documents, cơ sở đó là những documents liên kết ra, và các metadata cung cấp thông tin về các quan hệ.
- Relations
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">
+ Mở rộng
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: Array validates :last_name, presence: true has_many :books do def find_by_country country where(country: country).first end end end
[1] pry(main)> User.first.books.find_by_country "en" 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.1882ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x31950220 data=567a37ab6672613f3e000000>, "country"=>"en"}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.6782ms => #<Book _id: 567a39696672613f5f000000, created_at: 2015-12-23 06:04:25 UTC, updated_at: 2015-12-23 06:04:25 UTC, deleted_at: nil, name: "Name", author: "Author", description: "description", user_id: nil, country: "en", user_id: <BSON::ObjectId:0x30725100 data=567a37ab6672613f3e000000>>
+ Custom Relation Names Bạn có thể đặt tên cho mối quan hệ của bạn bất cứ điều gì bạn thích, nhưng nếu lớp không thể được suy ra bởi `Mongoid` từ tên gọi, và không thể ở phía đối diện, bạn sẽ phải cung cấp các `macro` với một số tùy chọn bổ sung để cho `Mongoid` có thể gọi ra được chúng.
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: Array validates :last_name, presence: true has_many :xyz, class_name: "Book" end
[2] pry(main)> User.first.xyz 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.9731ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x41428280 data=567a37ab6672613f3e000000>}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.5000ms => [#<Book _id: 567a39696672613f5f000000, created_at: 2015-12-23 06:04:25 UTC, updated_at: 2015-12-23 06:04:25 UTC, deleted_at: nil, name: "Name", author: "Author", description: "description", country: "en", user_id: <BSON::ObjectId:0x40116860 data=567a37ab6672613f3e000000>>, #<Book _id: 567a37fd6672613f3e000001, created_at: 2015-12-23 05:58:21 UTC, updated_at: 2015-12-23 05:58:21 UTC, deleted_at: nil, name: "Name", author: "Author", description: "description", country: nil, user_id: <BSON::ObjectId:0x40081300 data=567a37ab6672613f3e000000>>]
+ Validations<br> Điều quan trọng là phải lưu ý rằng theo mặc định, `Mongoid` sẽ xác nhận con của bất kỳ mối quan hệ đó được nạp vào bộ nhớ thông qua một `validates_associated`. Các mối quan hệ rằng điều này áp dụng cho là: + embeds_many + embeds_one + has_many + has_one + has_and_belongs_to_many Nếu bạn không muốn hành vi này, bạn có thể tắt nó đi khi xác định các mối quan hệ.
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: Array validates :last_name, presence: true has_many :books , validate: false end
+ Polymorphism Khi 1 document con thuộc về nhiều documents cha, bạn có thể thông báo cho `Mongoid` hỗ trợ bằng cách tùy chọn thêm vào để định nghĩa về cha của nó, và các tùy trọn `polymorphic` trên lớp con. Trên lớp con một trường bổ sung sẽ được lưu trữ mà chỉ ra loại của lớp con. `Polymorphic` được cho phép trên tất cả các mối quan hệ với các trường hợp ngoại lệ của `has_and_belongs_to_many`.
class Comment include Mongoid::Document field :content, type: String belongs_to :target, polymorphic: true end
class Post include Mongoid::Document field :content, type: String has_many :comments, as: :target end
class Picture include Mongoid::Document has_many :comments, as: :target end
[1] pry(main)> Comment.all.to_a MOPED: 127.0.0.1:27017 QUERY database=test_development collection=comments selector={} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.6912ms => [#<Comment _id: 567b55c06672612074000001, content: "description", target_type: "Post", target_id: <BSON::ObjectId:0x35268340 data=567b55876672612074000000>>, #<Comment _id: 567b55cb6672612074000002, content: "description2", target_type: "Post", target_id: <BSON::ObjectId:0x35267060 data=567b55876672612074000000>>, #<Comment _id: 567b55cd6672612074000003, content: "description3", target_type: "Post", target_id: <BSON::ObjectId:0x35231040 data=567b55876672612074000000>>, #<Comment _id: 567b55e96672612074000005, content: "description3", target_type: "Picture", target_id: <BSON::ObjectId:0x35229020 data=567b55da6672612074000004>>, #<Comment _id: 567b55ed6672612074000006, content: "description2", target_type: "Picture", target_id: <BSON::ObjectId:0x35226940 data=567b55da6672612074000004>>, #<Comment _id: 567b55f06672612074000007, content: "description1", target_type: "Picture", target_id: <BSON::ObjectId:0x35224960 data=567b55da6672612074000004>>]
[3] pry(main)> Post.first.comments.to_a MOPED: 127.0.0.1:27017 QUERY database=test_development collection=posts selector={"$query"=>{}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 1.0727ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=comments selector={"target_id"=><BSON::ObjectId:0x33209560 data=567b55876672612074000000>, "target_type"=>"Post"} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.7899ms => [#<Comment _id: 567b55c06672612074000001, content: "description", target_type: "Post", target_id: <BSON::ObjectId:0x33115140 data=567b55876672612074000000>>, #<Comment _id: 567b55cb6672612074000002, content: "description2", target_type: "Post", target_id: <BSON::ObjectId:0x33102300 data=567b55876672612074000000>>, #<Comment _id: 567b55cd6672612074000003, content: "description3", target_type: "Post", target_id: <BSON::ObjectId:0x33097560 data=567b55876672612074000000>>]
[4] pry(main)> Picture.first.comments.to_a MOPED: 127.0.0.1:27017 QUERY database=test_development collection=pictures selector={"$query"=>{}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.4518ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=comments selector={"target_id"=><BSON::ObjectId:0x21141100 data=567b55da6672612074000004>, "target_type"=>"Picture"} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.3860ms => [#<Comment _id: 567b55e96672612074000005, content: "description3", target_type: "Picture", target_id: <BSON::ObjectId:0x20960940 data=567b55da6672612074000004>>, #<Comment _id: 567b55ed6672612074000006, content: "description2", target_type: "Picture", target_id: <BSON::ObjectId:0x20957120 data=567b55da6672612074000004>>, #<Comment _id: 567b55f06672612074000007, content: "description1", target_type: "Picture", target_id: <BSON::ObjectId:0x20884620 data=567b55da6672612074000004>>]
+ Dependent Behaviour Bạn có thể cung cấp tùy chọn `dependent` vào các tham chiếu để hướng dẫn `Mongoid` cách xử lý tình huống mà một bên của mối quan hệ này sẽ bị xóa, hoặc là cố gắng để được xóa. Các tùy chọn như sau: + `:delete`: xóa documents con mà không cần chạy bất kì `model callbacks` + `:destroy`: Xóa documents con và chạy tất cả `model callbacks` + `:nullify`: Không xóa các documents con + `:restrict`: Thông báo lỗi khi child không có
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: Array validates :last_name, presence: true has_many :books , dependent: :delete end
[2] 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.1021ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x36030720 data=567a37ab6672613f3e000000>}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 17.0405ms => [#<Book _id: 567a39696672613f5f000000, created_at: 2015-12-23 06:04:25 UTC, updated_at: 2015-12-23 06:04:25 UTC, deleted_at: nil, name: "Name", author: "Author", description: "description", user_id: nil, country: "en", test_id: <BSON::ObjectId:0x34669480 data=567a37ab6672613f3e000000>>, #<Book _id: 567a37fd6672613f3e000001, created_at: 2015-12-23 05:58:21 UTC, updated_at: 2015-12-23 05:58:21 UTC, deleted_at: nil, name: "Name", author: "Author", description: "description", user_id: nil, country: nil, test_id: <BSON::ObjectId:0x34649740 data=567a37ab6672613f3e000000>>] [3] pry(main)> User.first.delete 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.9939ms MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"books", :query=>{"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x34041200 data=567a37ab6672613f3e000000>}} runtime: 1.1251ms MOPED: 127.0.0.1:27017 DELETE database=test_development collection=books selector={"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x34041200 data=567a37ab6672613f3e000000>} flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.6609ms MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=tests selector={"_id"=><BSON::ObjectId:0x34041200 data=567a37ab6672613f3e000000>} update={"$set"=>{"deleted_at"=>2015-12-24 09:34:32 +0700}} flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.5785ms => true
+ Autosaving Một khác biệt cốt lõi giữa `Mongoid` và `ActiveRecord` là `Mongoid` không tự động lưu lại các mối quan hệ con cho các `relational associations`. Đây là lý do hiệu suất của `Mongoid`.<br> Để kích hoạt một `autosave` vào một liên kết quan hệ thêm tùy chọn `autosave` đến quan hệ.<br> Lưu ý rằng chức năng `autosave` sẽ tự động được thêm vào một mối quan hệ khi sử dụng `accepts_nested_attributes_for` hoặc xác nhận sự hiện diện của các mối quan hệ.
[3] pry(main)> User.first.books MOPED: 127.0.0.1:27017 QUERY database=test_development collection=user selector={"$query"=>{"deleted_at"=>nil}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.6753ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "user_id"=><BSON::ObjectId:0x30727820 data=567b5c4866726124d1000000>}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.3228ms => [] [4] pry(main)> user = User.first 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.4337ms => #<User _id: 567b5c4866726124d1000000, created_at: 2015-12-24 02:45:28 UTC, updated_at: 2015-12-24 02:45:28 UTC, deleted_at: nil, first_name: "First Name", last_name: "Last Name", age: 18, address: ["HaNoi"]> [5] pry(main)> user.books.build(name: "name", author: "author", country: "en") => #<Book _id: 567b5d4266726124fd000001, created_at: nil, updated_at: nil, deleted_at: nil, name: "name", author: "author", description: nil, country: "en", user_id: <BSON::ObjectId:0x29381580 data=567b5c4866726124d1000000>> [6] pry(main)> user.save MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil, "user_id"=><BSON::ObjectId:0x29381580 data=567b5c4866726124d1000000>}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 0.8037ms MOPED: 127.0.0.1:27017 INSERT database=test_development collection=books documents=[{"_id"=><BSON::ObjectId:0x28139260 data=567b5d4266726124fd000001>, "deleted_at"=>nil, "name"=>"name", "author"=>"author", "country"=>"en", "user_id"=><BSON::ObjectId:0x29381580 data=567b5c4866726124d1000000>, "updated_at"=>2015-12-24 02:49:42 UTC, "created_at"=>2015-12-24 02:49:42 UTC}] flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 0.9621ms => true [7] pry(main)> user.books => [#<Book _id: 567b5d4266726124fd000001, created_at: 2015-12-24 02:49:42 UTC, updated_at: 2015-12-24 02:49:42 UTC, deleted_at: nil, name: "name", author: "author", description: nil, country: "en", user_id: <BSON::ObjectId:0x29381580 data=567b5c4866726124d1000000>>]
+ Existence Predicates<br> Tất cả các mối quan hệ có các vị từ sự tồn tại trên chúng trong các hình thức của `name?` và `has_name?` để kiểm tra xem các mối quan hệ có trống không.
[3] pry(main)> User.first.has_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: 32.3015ms MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"books", :query=>{"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x36370220 data=567b5c4866726124d1000000>}} runtime: 25.6522ms => true [4] 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: 0.5985ms MOPED: 127.0.0.1:27017 COMMAND database=test_development command={:count=>"books", :query=>{"deleted_at"=>nil, "test_id"=><BSON::ObjectId:0x34686280 data=567b5c4866726124d1000000>}} runtime: 0.3523ms => true
+ Autobuilding<br> Một với một mối quan hệ (`embeds_one`, `has_one)` có một tùy chọn `autobuild` thông báo cho Mongoid để khởi tạo một tài liệu mới khi quan hệ được truy cập và nó là `nil`.
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_one :book , dependent: :delete, autobuild: true end
[2] pry(main)> user = User.new => #<User _id: 5689bc4c667261104b000001, created_at: nil, updated_at: nil, deleted_at: nil, first_name: nil, last_name: nil, age: 18, address: nil> [3] pry(main)> user.book => #<Book _id: 5689bc4f667261104b000002, created_at: nil, updated_at: nil, deleted_at: nil, name: nil, author: nil, description: nil, country: nil, user_id: <BSON::ObjectId:0x39557320 data=5689bc4c667261104b000001>>
+ Touching<br> Bất kỳ mối quan hệ `belongs_to`, nó có thể bị treo,có một tùy chọn: tùy chọn `touch` sẽ gọi phương thức liên lạc vào nó và bất kỳ mối quan hệ cha với các tùy chọn định nghĩa khi các tài liệu cơ sở gọi `#touch`.
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 :user_id, type: Integer field :country, type: String belongs_to :user end
[4] pry(main)> book = Book.first MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} runtime: 0.7424ms MOPED: 127.0.0.1:27017 QUERY database=test_development collection=books selector={"$query"=>{"deleted_at"=>nil}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.3885ms => #<Book _id: 567b5d4266726124fd000001, created_at: 2015-12-24 02:49:42 UTC, updated_at: 2015-12-24 02:49:42 UTC, deleted_at: nil, name: "name", author: "author", description: nil, user_id: nil, country: "en", test_id: <BSON::ObjectId:0x25420200 data=567b5c4866726124d1000000>> [5] pry(main)> book.touch MOPED: 127.0.0.1:27017 UPDATE database=test_development collection=books selector={"_id"=><BSON::ObjectId:0x25423040 data=567b5d4266726124fd000001>} update={"$set"=>{"updated_at"=>2016-01-04 00:32:42 UTC}} flags=[] COMMAND database=test_development command={:getlasterror=>1, :w=>1} runtime: 1.3841ms => true