简体   繁体   中英

Mongoid: Querying embedded (recursively_embeds_many) documents

How can I find all documents that matches my criteria, independently of how deep it is embedded into a document?

Suppose I have a model that uses *recursively_embeds_many*. For example, a Comment that can have a reply. The reply, can have another reply and so on.

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

So the structure is basically:

  • Comment
    • content (string)
    • comments (list of Comment)

How can I query for all the Comment documents that has content equals "foo" ?

This solution uses Mongodb dot notation queries in combination with $or to pull relevant comments and then traverse them. You must specify max recursion level.

Please do not use on a live production anything! I don't want to be responsible if you crash your database :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

You should build indexes on your comments and subcomments if you want this to go faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM