[英]Retrieve records which have many-to-many association, using ruby and datamapper
I'm learning Sinatra, and I have read datamapper documentation and found this n to n relationship example: 我正在学习Sinatra,并且已经阅读了datamapper文档并发现了此n对n关系示例:
class Photo
include DataMapper::Resource
property :id, Serial
has n, :taggings
has n, :tags, :through => :taggings
end
class Tag
include DataMapper::Resource
property :id, Serial
has n, :taggings
has n, :photos, :through => :taggings
end
class Tagging
include DataMapper::Resource
belongs_to :tag, :key => true
belongs_to :photo, :key => true
end
What I understood from the code above is that one photo may have many or zero tags, and a tag may have many or zero photos. 从上面的代码中我了解到,一张照片可能有很多或零个标签,而一个标签可能有很多或零个照片。 How do I retrieve a list of photos with the tags associated to it already loaded.
如何检索带有已加载标签的照片列表。 I know datamapper uses the lazy approach, so it does not automatically loads the associated classes (in this case photo.tag).
我知道datamapper使用惰性方法,因此它不会自动加载关联的类(在本例中为photo.tag)。 So this:
所以这:
photos = Photo.all
would result in an array with Photo objects without the tags. 会导致包含带标签的Photo对象的数组。 Is there a way to automatically retrieve it or do I have to iterate over the array and set that manually?
有没有一种方法可以自动检索它,或者我必须遍历数组并手动进行设置?
Thanks in advance! 提前致谢!
I also have a database which has similar relations. 我也有一个具有相似关系的数据库。
Author
, Post
, Tag
are main models, and Subscribedtag
and Tagging
are built through has n, :through
. Author
, Post
, Tag
是主要模型, Subscribedtag
和Tagging
通过has n, :through
构建。
class Author
include DataMapper::Resource
property :id, Serial
property :email, String, :unique => true
property :password, String
property :first_name, String
property :last_name, String
property :bio, Text
property :phone, String, :unique => true
property :twitter, String, :unique => true
property :facebook, String, :unique => true
property :show_phone, Boolean, :default => false
property :show_facebook, Boolean, :default => false
property :show_twitter, Boolean, :default => false
property :is_admin, Boolean, :default => false
property :this_login, DateTime
property :last_login, DateTime
property :session_lasting, Integer, :default => 0
has n, :posts
has n, :subscribedtags
has n, :tags, :through => :subscribedtags
end
class Post
include DataMapper::Resource
property :id, Serial
property :title, String, :required => true
property :body, Text, :required => true
property :is_blog_post, Boolean, :default => true
property :viewed, Integer, :default => 0
property :featured, Boolean, :default => false
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :author
belongs_to :category
has n, :comments
has n, :taggings
has n, :tags, :through => :taggings
validates_length_of :title, :min => 3
validates_length_of :body, :min => 20
validates_format_of :title, :with => /\w/
#some other methods
end
class Tag
include DataMapper::Resource
property :id, Serial
property :name, String, :unique => true
has n, :taggings
has n, :posts, :through => :taggings
has n, :subscribedtags
has n, :authors, :through => :subscribedtags
validates_length_of :name, :min => 1
validates_format_of :name, :with => /\w/
# some other methods
end
class Tagging
include DataMapper::Resource
belongs_to :tag, :key => true
belongs_to :post, :key => true
end
class Subscribedtag
include DataMapper::Resource
belongs_to :tag, :key => true
belongs_to :author, :key => true
end
The way you've defined models, allows you to write queries, like that. 定义模型的方式允许您编写类似的查询。
2.2.0 :016 > kant = Tag.get(25) # getting tag instance with id 25 and assign it to variable named kant
=> #<Tag @id=25 @name="İmmanuil Kant">
2.2.0 :017 > kant.posts
=> #returns post instances which has this tag.
2.2.0 :018 > kant.posts.count # count of posts with this tag.
=> 2
2.2.0 :021 > kant.posts.first.author.first_name
=> "Ziya" # check my author class and first_name attribute.
Let's say I want to retrieve the tag instances which has no posts. 假设我要检索没有帖子的标签实例。 a simple ruby command.
一个简单的ruby命令。
2.2.0 :024 > Tag.each {|tnp| puts tnp.name if tnp.posts.count == 0}
Latın
Python
Ruby
Sosializm
Hegel
Or retrieving tags based on posts. 或根据帖子检索标签。
2.2.0 :034 > p = Post.get(9)
=> #<Post @id=9 @title="Why we use Lorem Ipsum" @body=<not loaded> @is_blog_post=false @viewed=0 @featured=false @created_at=#<DateTime: 2015-08-02T23:14:04+05:00 ((2457237j,65644s,0n),+18000s,2299161j)> @updated_at=#<DateTime: 2015-08-02T23:14:04+05:00 ((2457237j,65644s,0n),+18000s,2299161j)> @author_id=1 @category_id=1>
2.2.0 :035 > p.tags
=> [#<Tag @id=19 @name="Bundesliqa">]
retrieve posts which has no tag. 检索没有标签的帖子。
2.2.0 :043 > Post.each {|pnt| puts pnt.id if pnt.tags.count.zero?}
8 #post with id has no tags
2.2.0 :044 > Post.get(8).tags.count
=> 0
you can also query via other attributes. 您还可以通过其他属性进行查询。
2.2.0 :046 > Tag.first(:name => "Lorem").id
=> 30
iterate over results 遍历结果
2.2.0 :050 > Tag.first(:name => "Lorem").posts.each {|lorempost| puts lorempost.title} # printing post titles which are tagged with lorem.
Get'em all
qwerty
I also associated authors with tags through Subscribedtags
model, which I can easily check which author is subscribed to which tag, and vice versa. 我还通过
Subscribedtags
模型将作者与标签相关联,可以轻松地检查哪个作者订阅了哪个标签,反之亦然。
2.2.0 :055 > z = Author.get(1)
=> # returns details of author instance
2.2.0 :056 > z.tags
=> [#, #, #, #] => [#,#,#,#]
or querying via Subscribedtag 或通过Subscribedtag查询
2.2.0 :057 > z.subscribedtags
=> [#<Subscribedtag @tag_id=2 @author_id=1>, #<Subscribedtag @tag_id=4 @author_id=1>, #<Subscribedtag @tag_id=25 @author_id=1>, #<Subscribedtag @tag_id=30 @author_id=1>]
you can also define your own functions to utilize querying. 您还可以定义自己的函数以利用查询。 I've defined a subscribed_tags method which returns an array of subscribed tags' names.
我定义了一个subscribed_tags方法,该方法返回一个已订阅标签名称的数组。
2.2.0 :058 > z.subscribed_tags
=> ["Həyat", "Məstan", "İmmanuil Kant", "Lorem"]
If I want to retrieve the first_name attribute of a random author, who is subscribed to tag named "Lorem", 如果我要检索随机作者的first_name属性,该作者订阅了名为“ Lorem”的标签,
2.2.0 :062 > Tag.first(:name => "Lorem").authors.sample.first_name
=> "Ziya"
As an answer to your 2nd question, yes, most times you have to iterate. 作为对第二个问题的回答,是的,大多数时候您必须进行迭代。
Because Photos.all
return a collection of Photo object instances. 因为
Photos.all
返回Photo对象实例的集合。 And this instances individually has tag attributes, not the array consists of Photo instances. 而且此实例分别具有标签属性,而不是由Photo实例组成的数组。
if you call p = Photo.all; print p.tags;
如果您调用
p = Photo.all; print p.tags;
p = Photo.all; print p.tags;
it will return all tags associated with all photos, which may or may not be the thing you want. 它将返回与所有照片关联的所有标签,这可能是您想要的东西,也可能不是。
Feel free to ask more questions, if these are not enough. 如果这些还不够,请随时提出更多问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.