2010-11-08 77 views
2

我想将博客及其标签存储为单独的文档。Mongoid多对多问题

博客文章应该有tag_ids字段和标签不应该有blog_posts_ids字段。

Mongoid提供了许多开箱即用的关系,但它需要多对多关系的文档都有_ids字段。

class BlogPost 
    include Mongoid::Document 
    field :title 
    references_many :tags, :stored_as => :array, :inverse_of => :blog_posts 
end 

class Tag 
    include Mongoid::Document 
    field :name 
    # I DON'T WANT TO STORE BLOG_POSTS_IDS IN TAG DOCUMENT 
    references_many :blog_posts, :stored_as => :array, :inverse_of => :tags 
end 
+0

谁不能用mongoid代码。创建你自己的方法。 – shingara 2010-11-08 08:29:52

回答

4

你可以绕过它的方法伪造的另一面:帖=> [ARRAY_OF_BLOG_ARTICLES]}} 您可以创建一个formatl标签类或使用协会

class BlogPost 
    include Mongoid::Document 
    field :title 
    references_many :tags, :stored_as => :array, :inverse_of => :blog_posts 
end 

class Tag 
    include Mongoid::Document 
    field :name 

    def blog_posts 
    # will match all BlogPost records where the tag_ids array contains self.id 
    BlogPost.where(:tag_ids => self.id) 
    end 
end 

很显然,这并不是全功能为:references_many,但你可以在很多一对多关系的类似假冒其他方面。例如,如果您希望能够为标签分配新的blog_post,则可以将简单的create_blog_post方法添加到Tag

对于很多现实世界的情况,只要保持方法简单并且不会被带走,这种方法就是实用的。

2

地图减少可能是你的答案。看看到MongoDB的映射减少和使用永久收藏输出标签

class BlogPost 
    include Mongoid::Document 
    field :title 
    field :tags, :type => Array 
    references_many :tags, :stored_as => :array, :inverse_of => :blog_posts 
end 

map =<<JS 
    function(){ 
    if(!this.tags){ 
     return; 
    } 
    for(index in this.tags){ 
     emit(this.tags[index],{count:1,posts:[this.post.id]}) 
    } 
    } 
JS 

reduce =<<JS 
    function(key,values){ 
    var tagging = {count:0,posts:new Array()} 
    values.forEach (function(val) { 
     tagging.count++; 
     tagging.posts.push(val.posts[0]) 
    }); 
    return tagging; 
    } 
JS 

BlogPost.collection.map_reduce(map,reduce,{:out => 'tags',:keeptemp => true}) 

结果集总是{ID,值}其中{:ID =>标记名:价值=> {:数=> NUMBER_OF_TIMES_TAG_IS_USED ,:在Tag

Mongoid.master.collection("tags") 

http://api.mongodb.org/ruby/1.1.2/Mongo/Collection.html#map_reduce-instance_methodt