Search code examples
mongodbpymongopymongo-3.x

How do I get projection $ to work in pymongo?


I have a query which runs in the mongo repl.

I have a collection of documents that look somewhat like this...

[{              
        "_id" : ObjectId("5b6b6959828619572d48a9da"),
        "files" : [                                                                                     
                {                                                                         
                        "original_filename" : "test_file1.csv",                                                                                                                                                                                                               
                        "s3_key" : "intake/uploads/3edc78aa-2275-45ad-afcb-23bf4a765591/test_file1.csv"                                                                                                                                                                      
                },                                              
                {                                                                                                                                                                                                                                                             
                        "original_filename" : "test_file2.csv",                                                                                                                                                                                                              
                        "s3_key" : "intake/uploads/3edc78aa-2275-45ad-afcb-23bf4a765591/test_file2.csv"          
                }
        ],
        "created_at" : ISODate("2018-08-08T22:06:17.366Z")                                                         
}]

In the mongo repl I can do:

db.uploads.find({"_id": ObjectId("5b6b6959828619572d48a9da"), "files.original_filename": "test_file1.csv"}, {"files.$": 1})

And I receive the data exactly as I want it:

{                                                                                                        
        "_id" : ObjectId("5b6b6959828619572d48a9da"),                                                                        
        "files" : [                                                                                                                                                                                                                                                          
                {                                                                                                            
                        "original_filename" : "test_file2.csv",                                                                                                                                                                                                              
                        "s3_key" : "intake/uploads/3edc78aa-2275-45ad-afcb-23bf4a765591/test_file2.csv"                      
                }                                                                                                                                                                                                                                                            
        ]                                                                                                                    
} 

But in pymongo I do:

query = {
    '_id': upload_id,
    'files.original_filename': 'test_file1.csv'
}
projection = {'files.$': 1}
result = list(self.uploads.find(query, projection))

And result is wrong:

[{'files': {}, '_id': ObjectId('5b6b6959828619572d48a9da')}]

WHY?!?


Solution

  •         query = {
                '_id': upload_id
            }
            projection = {
                'files': {
                    '$elemMatch': {
                        'original_filename': original_filename
                    }
                }
            }
            result = list(self.uploads.find(query, projection))
    

    I used this projection instead and I seem to get the data I want. I would still like to know why, and if there are other better ways of doing this.