Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return embedded documents in query

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.

like image 546
vrish88 Avatar asked Feb 28 '10 00:02

vrish88


People also ask

How do I query embedded files in MongoDB?

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.

How would you query an array of embedded documents in MongoDB?

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.

What is embedded document in MongoDB?

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.

How do you match a nested field in MongoDB?

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.


1 Answers

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.

like image 125
Michael Bleigh Avatar answered Sep 21 '22 02:09

Michael Bleigh