我想将博客及其标签存储为单独的文档。
博客帖子应该有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 :(得分:4)
您可以使用Tag
上的方法绕过它来伪造关联的另一面
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
方法。
对于许多现实世界的情况,这种方法是实用的,只要你保持方法简单并且不会被带走。
答案 1 :(得分:2)
Map Reduce可能是您的答案。查看MongoDB map reduce并使用标签的永久集合输出
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,values},其中{:id =&gt; TAGNAME,:value =&gt; {:count =&gt; NUMBER_OF_TIMES_TAG_IS_USED,:posts =&gt; [ARRAY_OF_BLOG_ARTICLES]}} 您可以创建formatl Tag类或使用:
Mongoid.master.collection("tags")
http://api.mongodb.org/ruby/1.1.2/Mongo/Collection.html#map_reduce-instance_methodt