views:

354

answers:

1

Is it possible to perform a query and return the embedded documents?

Currently, I have:

class Post
  include MongoMapper::Document

  many :comments
end

class Comment
  include MongoMapper::EmbeddedDocument

  belongs_to :post

  key :author
  key :date
  key :body
end

Here is a query that is almost there:

Post.all("comments.date" => {"$gt" => 3.days.ago})

This will return all the post objects but not the comments. I guess I could do something like:

Post.all("comments.date" => {"$gt" => 3.days.ago}).map(&:comments)

But this would return all comments from the posts. I'd like to get all of the comments that met this condition. Perhaps Comment should not be embedded.

+3  A: 

I assume you're looking for all comments newer than three days ago? Since your Comments are just embedded documents, they do not exist without the Post object so there's no way to "query" them separately (this is actually a future feature of MongoDB). However, you could easily add a convenience method to help you out:

class Comment
  include MongoMapper::EmbeddedDocument

  def self.latest
    Post.all(:conditions => {"comments.date" => {"$gt" => 3.days.ago}}).map{|p| p.comments}.flatten
  end
end

This method would get you all of the comments that have been updated in the last three days but they would not entirely be in order. A better solution might be to use Map/Reduce to pull the latest comments:

class Comment
  include MongoMapper::EmbeddedDocument

  def self.latest
    map = <<-JS
    function(){ 
      this.comments.forEach(function(comment) {
        emit(comment.created_at, comment)
      });
    }
    JS
    r = "function(k,vals){return 1;}" 
    q = {'comments.created_at' => {'$gt' => 3.days.ago}}

    Post.collection.map_reduce(m,r,:query => q).sort([['$natural',-1]])
  end
end

Caveat: the above is completely untested code and just exists as an example, but theoretically should return all comments from the last three days sorted in descending order.

Michael Bleigh
Do you think it would be better to put the comments into their own collection?
vrish88
Honestly it depends on the focus of your app. If your app is mostly about commenting, perhaps. However, there are other solutions to consider as well. For instance, you could create a de-normalized capped collection called "comments" that simply stored the latest, oh, 100 or so comments in a separate collection. Then you could display that feed when necessary, but display the Post feed otherwise. NoSQL systems encourage experimentation in data design, find what works best for you!
Michael Bleigh