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.
Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.
Use the Array Index to Query for a Field in the Embedded Document. Using dot notation, you can specify query conditions for field in a document at a particular index or position of the array. The array uses zero-based indexing. When querying using dot notation, the field and index must be inside quotation marks.
MongoDB provides you a cool feature which is known as Embedded or Nested Document. Embedded document or nested documents are those types of documents which contain a document inside another document.
Match an Embedded/Nested Document To specify an equality condition on a field that is an embedded/nested document, use the query filter document { <field>: <value> } where <value> is the document to match.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With