使用ruby和datamapper检索具有多对多关联的记录

时间:2015-10-10 19:27:16

标签: ruby sinatra datamapper

我正在学习Sinatra,我已阅读datamapper文档并找到了这个n到n的关系示例:

img {-webkit-filter: grayscale(100%); filter: grayscale(100%);}
img {-webkit-filter: invert(100%); filter: invert(100%);}

我从上面的代码中理解的是,一张照片可能有很多或零个标签,而标签可能有很多或零照片。如何检索已加载相关标签的照片列表。我知道datamapper使用惰性方法,因此它不会自动加载关联的类(在本例中为photo.tag)。所以这个:

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

将导致带有没有标记的Photo对象的数组。有没有办法自动检索它,还是我必须迭代数组并手动设置?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我也有一个类似关系的数据库。 AuthorPostTag是主要模型,SubscribedtagTagging是通过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

您定义模型的方式允许您编写类似的查询。

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.

假设我想要检索没有帖子的标签实例。 一个简单的ruby命令。

2.2.0 :024 > Tag.each {|tnp| puts tnp.name if tnp.posts.count == 0}
Latın
Python
Ruby
Sosializm
Hegel

或根据帖子检索标签。

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">] 

检索没有标记的帖子。

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 

您还可以通过其他属性进行查询。

2.2.0 :046 > Tag.first(:name => "Lorem").id
 => 30 

迭代结果

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

我还通过Subscribedtags模型将作者与标签相关联,我可以轻松检查哪个作者订阅了哪个标签,反之亦然。

2.2.0 :055 > z = Author.get(1)
 => # returns details of author instance
2.2.0 :056 > z.tags

=&GT; [#,#,#,#]

或通过Subscribed标签查询

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>] 

您还可以定义自己的功能以利用查询功能。我已经定义了一个subscribed_tags方法,它返回一个订阅标签名称的数组。

2.2.0 :058 > z.subscribed_tags
 => ["Həyat", "Məstan", "İmmanuil Kant", "Lorem"] 

如果我想检索随机作者的first_name属性,谁订阅了名为“Lorem”的标签,

2.2.0 :062 > Tag.first(:name => "Lorem").authors.sample.first_name
 => "Ziya" 

作为对第二个问题的回答,是的,大多数情况下你必须进行迭代。

因为Photos.all返回Photo对象实例的集合。并且此实例单独具有标记属性,而不是数组由Photo实例组成。

如果您致电p = Photo.all; print p.tags;,它将返回与所有照片相关联的所有标签,这些标签可能是您想要的,也可能不是。

如果这些还不够,请随意提出更多问题。