1

I have a simple collection.

> db.y.find({}, {'_id': 1})
{ "_id" : ObjectId("5908e63cd15fa104356eaf64") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf65") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf66") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf67") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf68") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf69") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf6a") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf6b") }

I want to operate a simple aggregation pipeline (largely simplified for the explanation)

I run this Mongo shell script:

print('find')
result = db.y.find({ '_id': ObjectId("5908e63cd15fa104356eaf64") }, {'_id':1})
while ( result.hasNext() ) { printjson( result.next() ); }

print('aggregate match direct')
result = db.y.aggregate( [ {'$match': {'_id': ObjectId("5908e63cd15fa104356eaf64") } }, {'$project': {'_id': 1}} ] )
while ( result.hasNext() ) { printjson( result.next() ); }

print('aggregate match with $eq')
result = db.y.aggregate( [ {'$match': {'_id': {'$eq': ObjectId("5908e63cd15fa104356eaf64") } } }, {'$project': {'_id': 1}} ] )
while ( result.hasNext() ) { printjson( result.next() ); }

print('aggregate match with $ne')
result = db.y.aggregate( [ {'$match': {'_id': {'$ne': ObjectId("5908e63cd15fa104356eaf64") } } }, {'$project': {'_id': 1}}, {'$limit': 5} ] )
while ( result.hasNext() ) { printjson( result.next() ); }

with this result (which is absolutely correct)

find
{ "_id" : ObjectId("5908e63cd15fa104356eaf64") }
aggregate match direct
{ "_id" : ObjectId("5908e63cd15fa104356eaf64") }
aggregate match with $eq
{ "_id" : ObjectId("5908e63cd15fa104356eaf64") }
aggregate match with $ne
{ "_id" : ObjectId("5908e63cd15fa104356eaf65") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf66") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf67") }
{ "_id" : ObjectId("5908e63cd15fa104356eaf68") }

Then I want to convert this to python as follows:

...
print('find')

result = y.find({ '_id': 'ObjectId("5908e63cd15fa104356eaf64")' }, {'_id':1})

for i, o in enumerate(result):
    print(i, o)

print('aggregate match direct')

result = y.aggregate( [ {'$match': {'_id': 'ObjectId("5908e63cd15fa104356eaf64")' } }, {'$project': {'_id': 1} } ] )

for i, o in enumerate(result):
    print(i, o)

print('aggregate match with $eq')

result = y.aggregate( [ {'$match': {'_id': {'$eq': 'ObjectId("5908e63cd15fa104356eaf64")' } } }, {'$project': {'_id': 1} } ] )

for i, o in enumerate(result):
    print(i, o)

print('aggregate match with $ne')

result = y.aggregate( [ {'$match': {'_id': {'$ne': 'ObjectId("5908e63cd15fa104356eaf64")' } } }, {'$project': {'_id': 1} }, {'$limit': 5} ] )

for i, o in enumerate(result):
    print(i, o)

with this result:

find
aggregate match direct
aggregate match with $eq
aggregate match with $ne
0 {'_id': ObjectId('5908e63cd15fa104356eaf64')}
1 {'_id': ObjectId('5908e63cd15fa104356eaf65')}
2 {'_id': ObjectId('5908e63cd15fa104356eaf66')}
3 {'_id': ObjectId('5908e63cd15fa104356eaf67')}
4 {'_id': ObjectId('5908e63cd15fa104356eaf68')}

Conclusion:

The $match operations never take the ObjectId syntax into account.

How to write it properly ??

Thanks for any hint

Christian

1 Answers1

1

You have to use the ObjectId class in the standard library

from bson.objectid import ObjectId
result = y.find({ '_id': ObjectId("5908e63cd15fa104356eaf64") }, {'_id':1})

Possibly Related

Right now the match and find fields are asking if the _id is a string named "ObjectId("5908e63cd15fa104356eaf64)". But in Python, you have to assign a unique identifier first with the ObjectId Class

Your last match is actually printing everything because you are asking if all _ids are not equal to the string "ObjectId("5908e63cd15fa104356eaf64)", not the ObjectId

Community
  • 1
  • 1
jwillis0720
  • 4,329
  • 8
  • 41
  • 74