2010-07-15 5 views
3

Je commence juste un nouveau projet Rails 3 en utilisant Mongoid ORM pour MongoDB. Il y a juste une chose que je n'arrive pas à comprendre, et c'est comment avoir une relation plusieurs-à-plusieurs. Maintenant, il y a de bonnes chances que j'aborde mal ce problème, mais autant que je sache, il y a au moins deux conteneurs dans mon projet qui ont besoin d'une relation plusieurs-à-plusieurs. Je préférerais traiter les deux modèles comme des modèles «de première classe» et les attribuer chacun avec son propre conteneur.Repenser les relations relationnelles plusieurs-à-plusieurs pour MongoDB

C'est la façon la plus simple que je peux penser à structurer mon many-to-many:

// Javascript pseudo modeling 
// -------------------- Apps 
{ 
    app: { 
    _id: "app1", 
    name: "A", 
    event_ids: ["event1","event2"] 
    } 
} 

{ 
    app: { 
    _id: "app2", 
    name: "B", 
    event_ids: ["event1"] 
    } 
} 

// -------------------- Events 

{ 
    event: { 
    _id: "event1", 
    name: "Event 1", 
    } 
} 

{ 
    event: { 
    _id: "event2", 
    name: "Event 2", 
    } 
} 

Pour autant que je peux dire que c'est la quantité minimum d'informations ont besoin d'en déduire un nombre-to beaucoup de relation. Mon hypothèse est que je devrais avoir une procédure de réduction de carte pour déterminer quelles applications appartiennent à un événement. Je devrais également écrire post-commit/save hooks sur Event pour mettre à jour App.event_ids si une application est ajoutée ou supprimée d'un modèle d'événement.

Suis-je sur la bonne voie ici? Si quelqu'un a des exemples de code Mongoid ou Mongomapper d'une relation many-to-many, pourriez-vous partager s'il vous plaît.

Répondre

1

J'ai été en mesure d'implémenter cette conception en utilisant Mongoid. J'ai écrit des tests approfondis et j'ai réussi à faire fonctionner ma solution; Cependant, je ne suis pas satisfait de ma mise en œuvre. Je crois que ma mise en œuvre serait difficile à maintenir.

Je poste ma solution non-élégante ici. Espérons que cela aidera quelqu'un avec le début d'une meilleure mise en œuvre.

class App 
    include Mongoid::Document 
    field :name 

    references_one :account 
    references_many :events, :stored_as => :array, :inverse_of => :apps 

    validates_presence_of :name 
end 

class Event 
    include Mongoid::Document 
    field :name, :type => String 

    references_one :account 

    validates_presence_of :name, :account 

    before_destroy :remove_app_associations 

    def apps 
    App.where(:event_ids => self.id).to_a 
    end 

    def apps= app_array 
    unless app_array.kind_of?(Array) 
     app_array = [app_array] 
    end 
    # disassociate existing apps that are not included in app_array 
    disassociate_apps App.where(:event_ids => self.id).excludes(:id => app_array.map(&:id)).to_a 
    # find existing app relationship ids 
    existing_relationship_ids = App.where(:event_ids => self.id, :only => [:id]).map(&:id) 
    # filter out existing relationship ids before making the new relationship to app 
    push_apps app_array.reject { |app| existing_relationship_ids.include?(app.id) } 
    end 

    def push_app app 
    unless app.event_ids.include?(self.id) 
     app.event_ids << self.id 
     app.save! 
    end 
    end 

    def disassociate_app app 
    if app.event_ids.include?(self.id) 
     app.event_ids -= [self.id] 
     app.save! 
    end 
    end 

    def push_apps app_array 
    app_array.each { |app| push_app(app) } 
    end 

    def disassociate_apps app_array 
    app_array.each { |app| disassociate_app(app) } 
    end 

    def remove_app_associations 
    disassociate_apps apps 
    end 

end 
1

Votre structure peut fonctionner et vous n'avez pas besoin d'une fonction mapreduce pour déterminer quelles applications appartiennent à un événement. Vous pouvez interroger la collection d'applications sur un eventid. Vous pouvez indexer le champ collection.event_ids.

Si vous ne souhaitez pas rechercher des applications sur un eventid mais sur un nom d'événement, vous devez ajouter ce nom d'événement à la collection d'applications (dénormalisation). Cela signifie que vous devez également mettre à jour la collection d'applications lorsque le nom d'un événement change. Je ne sais pas si cela arrive très souvent?

Vous devez souvent dénormaliser lorsque vous utilisez MongoDB, donc vous ne stockez pas la quantité minimale d'informations mais vous stockez certaines choses "deux fois".

+0

Merci. C'est l'approche que j'ai prise. Je poste comment j'ai implémenté ceci ci-dessous. –