本文介绍了使用ruby和datamapper检索具有多对多关联的记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Sinatra,并且阅读了datamapper文档,并找到了该n对n关系示例:

  class Photo 
包括DataMapper :: Resource
属性:id,序列
具有n,:taggings
具有n,:tags,:through => :taggings
end
类Tag
包括DataMapper :: Resource
属性:id,序列
具有n,:taggings
具有n,:photos, :through => :taggings
end
类标记
包括DataMapper :: Resource
属居到:tag,:key =>真
属于:photo,:key =>真正的
结束

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

 照片= Photo.all 

会导致数组中包含带标签的Photo对象。有没有一种方法可以自动检索它,或者我必须遍历数组并手动进行设置?



预先感谢!

解决方案

我也有一个具有相似关系的数据库。 Author Post Tag 是主要模型,而 Subscribedtag Tagging 是通过 has n,:through 构建的。

  class作者
include DataMapper :: Resource

property:id,Serial
属性:email,String,:unique => true
属性:password,字符串
属性:first_name,字符串
属性:last_name,字符串
属性:bio,文本
属性:phone,String,:unique = > true
属性:twitter,String,:unique => true
属性:facebook,String,:unique => true
属性:show_phone,布尔值,:default => false
属性:show_facebook,布尔值,:default => false
属性:show_twitter,布尔值,:default => false
属性:is_admin,布尔值,:default => false
属性:this_login,DateTime
属性:last_login,DateTime
属性:session_lasting,Integer,:default => 0

具有n,:posts
具有n,:subscribedtags
具有n,:tags,:through => :subscribedtags
结束

类Post
包括DataMapper :: Resource

属性:id,序列
属性:title,String,:必填=> true
属性:body,Text,:required => true
属性:is_blog_post,布尔值,:default => true
属性:已查看,整数,:默认=> 0
属性:featured,Boolean,:default => false
属性:created_at,DateTime
属性:updated_at,DateTime

归属_至:作者
属性_至:类别
具有n,:注释
具有n,:taggings
具有n,:tags,:through => :taggings

validates_length_of:title,:min => 3
validates_length_of:body,:min => 20
validates_format_of:title,:with => / \w /

#一些其他方法

end


class Tag
include DataMapper :: Resource

属性:id,序列
属性:name,String,:unique => true

具有n,:taggings
具有n,:posts,:through => :taggings
具有n,:subscribedtags
具有n,:authors,:through => :subscribedtags

validates_length_of:name,:min => 1
validates_format_of:name,:with => / \w /

#其他一些方法

end

类标记
包括DataMapper :: Resource

属于:tag,:key =>真
属于:post,:key =>真
结束

类Subscribedtag
include DataMapper :: Resource

属于:tag,:key =>真
属于:作者,:key => true
end

定义模型的方式使您可以编写查询,例如那。

  2.2.0:016> kant = Tag.get(25)#获取ID为25的标签实例,并将其分配给名为kant 
=>的变量。 #< Tag @ id = 25 @ name =İmmanuilKant>
2.2.0:017> kant.posts
=> #return具有此标签的帖子实例。
2.2.0:018> kant.posts.count#具有此标签的帖子数。
=> 2
2.2.0:021> kant.posts.first.author.first_name
=> Ziya#检查我的作者类和first_name属性。

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

  2.2.0:024> Tag.each {| tnp |如果tnp.posts.count == 0,则输入tnp.name。
Latın
Python
Ruby
Sosializm
Hegel

或基于帖子检索标签。

  2.2 .0:034> p = Post.get(9)
=> #< Post @ id = 9 @ title =我们为什么使用Lorem Ipsum @ body =<未加载> @ 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 |如果pnt.tags.count.zero?放置pnt.id?} 
8#id为#post的标签没有标签
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}#打印带有lorem标签的帖子标题。 
全部获取
qwerty

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

  2.2.0:055> z = Author.get(1)
=> #返回作者实例
2.2.0:056>的详细信息z.tags

=> [#,#,#,#]



或通过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>]

您还可以定义自己的函数来利用查询。我定义了一个subscriptiond_tags方法,该方法返回一个已订阅标签名称的数组。

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

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

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

作为第二个问题的答案,是的,大多数时候您必须进行迭代。 / p>

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



如果您调用 p = Photo.all; print p.tags; 它将返回与所有照片关联的所有标签,可能不是您想要的东西。



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


I'm learning Sinatra, and I have read datamapper documentation and found this n to n relationship example:

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). So this:

photos = Photo.all

would result in an array with Photo objects without the tags. 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.

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.

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.

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

=> [#, #, #, #]

or querying via 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.

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

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. And this instances individually has tag attributes, not the array consists of Photo instances.

if you call 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.

这篇关于使用ruby和datamapper检索具有多对多关联的记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-07 09:05