2013-01-17 3 views
1

Comment puis-je trouver tous les documents qui correspond à mes critères, indépendamment de la profondeur, il est intégré dans un document?MongoId: Interrogation embarqués documents (recursively_embeds_many)

Supposons que j'ai un modèle qui utilise * recursively_embeds_many *. Par exemple, un commentaire qui peut avoir une réponse. La réponse, peut avoir une autre réponse et ainsi de suite.

class Comment 
    include Mongoid::Document 
    field :content, type: String 
    recursively_embeds_many # this makes comment.child_comments available 
end 

Ainsi, la structure est essentiellement:

  • Commentaire
      contenu
    • (string)
    • commentaires (liste des commentaires)

Comment puis-je requête pour tous les documents de commentaires qui a contenu égal à « foo »?

Répondre

3

Cette solution utilise des requêtes de notation par points MongoDB en combinaison avec $or pour tirer des commentaires pertinents et de les traverser. Vous devez spécifier le niveau de récursivité maximale.

S'il vous plaît ne pas utiliser quoi que ce soit sur une production en direct! Je ne veux pas être responsable si vous vous écrasez votre base de données: P

# app/models/comment.rb 
class Comment 
    include Mongoid::Document 
    field :content, type: String 
    recursively_embeds_many # this makes comment.child_comments available 

    # 'n' is the maximum level of recursion to check. 
    def self.each_matching_comment(n, q, &block) 
    queries = 0.upto(n).collect { |l| level_n_query(l, q) } 
    Comment.or(*queries).each { |c| c.each_matching_subcomment(q, &block) } 
    end 

    def self.level_n_query(n, q) 
    key = (['child_comments'] * n).join('.') + 'content' 
    return {key => q} 
    end 

    # recursive, returns array of all subcomments that match q including self 
    def each_matching_subcomment(q, &block) 
    yield self if self.content == q 
    self.child_comments.each { |c| c.each_matching_subcomment(q, &block) } 
    end 
end 

# hits each comment/subcomment up to level 10 with matching content once 
Comment.each_matching_comment(10, 'content to match') do |comment| 
    puts comment.id 
end 

Vous devez créer des index sur vos commentaires et si vous voulez les sous commentaires que cela aille plus vite.

Questions connexes