2010-11-08 5 views
2

Je souhaite stocker le blog et ses tags dans des documents distincts.Mongoid problème plusieurs à plusieurs

Le blog devrait contenir un champ tag_ids et le tag blog_posts_ids ne devrait pas figurer sur le tag.

Mongoid fournit de nombreuses relations à partir de la boîte, mais il exige que les deux documents de plusieurs à plusieurs relations aient un champ _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

qui ne peut pas réellement avec le code mongoide. Créez vous-même votre méthode. – shingara

Répondre

4

Vous pouvez la contourner avec une méthode sur Tag pour simuler l'autre côté de la association

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 

De toute évidence, ce n'est pas aussi complet que :references_many, mais vous pouvez d'autres aspects de la même faux de nombreux à-plusieurs. Par exemple, si vous souhaitez pouvoir attribuer un nouveau blog_post à une balise, vous pouvez ajouter une méthode simple create_blog_post à Tag.

Pour de nombreuses situations du monde réel, ce type d'approche est pratique tant que vous gardez les méthodes simples et ne vous laissez pas emporter.

2

La réduction de carte peut être votre réponse. Regardez pour carte MongoDB réduire et utiliser la sortie de la collection permanente pour les balises

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}) 

La collection de résultat est toujours {id, valeurs} où {: id => TAGNAME,: valeur => {: count => NUMBER_OF_TIMES_TAG_IS_USED ,: messages => [ARRAY_OF_BLOG_ARTICLES]}} Vous pouvez créer une classe formatl Tag ou de l'utilisation:

Mongoid.master.collection("tags") 

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

Questions connexes