Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyMongo - Querying list of embedded documents

There are a few posts here about this but not exactly what I'm after.

I have a document that contains a list of embedded documents:

{
   "_id": 1234
   "name": "joe"
   "comments": [
       {"type": "text", "content": "my content"},
       {"type": "image", "content": "my_content"}
       {"type": "image", "content": "my_content"}
   ]

}

I want to run one query that gets a set of documents then I was hoping to run a secondary query to search the "comments" list from that initial query set.

e.g p = db.people.find({"some":"condition"}) and then search the embedded docs like p.find({"type":"image"}

This obviously doesn't work. Just wondering if there's a way to do this without having to run 2 separate queries over the parent document collection again?

like image 873
GivP Avatar asked Oct 12 '25 18:10

GivP


2 Answers

If you want to just find the items in a collection that satisfy a given condition and also satisfy {"type": "image"} in the comments array, you can do that in a single query:

p = db.people.find({"some": "condition", "comments.type": "image"})

See the dot notation page for more info.

If you do actually need the whole thing, and you're interested in specific sub-items from said result, then the best method that I can think of is just to slurp in the result into a list, and check it in Python. Do any PyMongo gurus have anything to say on this? Note that, if your dataset is large, then this is not a good idea.

p = list(db.people.find({"some": "condition"})

# A little verbose, but...
image_p = [item for item in p
           if any(comment['type'] == 'image'
                  for comment in item['comments'])]

...
like image 128
voithos Avatar answered Oct 15 '25 17:10

voithos


The problem using only find with the dot notation is that you'll always get the whole document and not only the sub document.

use mongodb 2.2 to be able to use Aggregation.

look here

nb: $ElementMatch does not iteration when it is used with positional element (something.$.someattribute), it will exit just after the first document matched, so use aggregation to get all the sub documents that matches :)

like image 37
Abdelouahab Pp Avatar answered Oct 15 '25 18:10

Abdelouahab Pp