Mongoid много ко многим проблема - PullRequest
2 голосов
/ 08 ноября 2010

Я хочу хранить блог и его теги как отдельные документы.

В блоге должно быть поле 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

Ответы [ 2 ]

4 голосов
/ 18 ноября 2010

Вы можете обойти это с помощью метода 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.

Для многих реальных ситуаций такой подход практичен, если вы придерживаетесь простых методов и не увлекаетесь.

2 голосов
/ 09 ноября 2010

Карта Уменьшить может быть Ваш ответ. Посмотрите на карту 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, values}, где {: id => TAGNAME,: value => {: count => NUMBER_OF_TIMES_TAG_IS_USED,: posts => [ARRAY_OF_BLOG_ARTICLES]}} Вы можете создать формат тега класса или использовать:

Mongoid.master.collection("tags")

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

...