Reputation: 127
I have a Mongo Document with an Embedded document list inside(example below). I'm trying to run an aggregation that will return the full document with only the matched objects from within the list.
Example Collection Data
{
"make": "Toyota",
"color": "blue",
"tires": [{
"make": "Mishlen",
"size": 185
}, {
"make": "Mishlen",
"size": 210
}]
}
I managed to make it work in MongoDB with the following query
db.cars.aggregate(
[
{
$match: {$and: [{"tires.size": {$gt: 200}}]}
},
{
$addFields: {
"tires": {
$filter: {
input: '$tires',
as: 'tires',
cond: {$gt: ['$$tires.size', 200]}
}
}
}
},
{
$limit: 100
},
{
$skip: 0
}
])
I'm trying to run the same aggregation in mongoengine and it's returning an empty list everytime.
pipeline = [
{
"$match": {"$and": [{"tires.size": {"$gt": 200}}]}
},
{
"$addFields": {
"tires": {
"$filter": {
"input": "$tires",
"as": "tires",
"cond": {"$and": [{"$gt": ["$$tires.size", 200]}]}
}
}
}
}
]
self.obj_type.objects.aggregate(*pipeline)
What am I doing wrong?
UPDATE
My problem was much easier than I thought, I missed that I was passing the numbers as a string instead of int in python. Thank everyone for the help
Upvotes: 4
Views: 2036
Reputation: 6354
After inserting the sample document that you provided, I don't have any particular problem to run the aggregation with the pipeline you provided. See below:
class Tire(EmbeddedDocument):
make = StringField()
size = IntField()
class Car(Document):
make = StringField()
color = StringField()
tires = EmbeddedDocumentListField(Tire)
meta = {'collection': 'cars'}
pipeline = [
{
"$match": {"$and": [{"tires.size": {"$gt": 200}}]}
},
{
"$addFields": {
"tires": {
"$filter": {
"input": "$tires",
"as": "tires",
"cond": {"$and": [{"$gt": ["$$tires.size", 200]}]}
}
}
}
}
]
# Verify aggregation pipeline runs fine with the driver (pymongo)
coll = Car._get_collection()
pymongo_result = list(coll.aggregate(pipeline))
assert len(pymongo_result) == 1
# Run same aggregation pipeline with MongoEngine
mongoengine_result = list(Car.objects.aggregate(*pipeline))
assert len(mongoengine_result) == 1
result = [
{'_id': ObjectId('5e0a5c8e7c57cd9b300710fb'),
'color': 'blue',
'make': 'Toyota',
'tires': [{'make': 'Mishlen', 'size': 210.0}]
}
]
assert mongoengine_result == pymongo_result == result
I've used the latest mongoengine version but AFAIK there was no major change in the aggregation wrapper of MongoEngine lately. It is possible that the problem resides in self.obj_type.objects
on your end, try from a fresh queryset like I do (i.e YourDocumentClass.objects
) to see if it makes a difference.
Upvotes: 2
Reputation: 177
Below workflow would be the most simple
pipeline = [
{
$unwind: "$tires"
},
{
"$match": {"$and": [{"tires.size": {"$gt": 200}}]}
},
{
$group : {
_id : "$make",
tires: { $push: "$tires" }
}
}
]
self.obj_type.objects.aggregate(*pipeline)
Upvotes: 1