so I have this test data for instance in mongo, Cart model:
{
"_id" : ObjectId("55eb513c516ddc8fa6e68886"),
"user" : ObjectId("55e3f236516ddc78296968be"),
"items" : [
{
"item" : ObjectId("55eb10b8516ddc7508dba7c2"),
"quantity" : 1,
"added_date" : ISODate("2015-09-05T20:32:16.527Z"),
"coupons" : ObjectId("55eb10cd516ddc751d3d5e25"),
"order_type" : [
"in_store",
"curbside"
]
},
{
"item" : ObjectId("55eb10b8516ddc7508dba7cc"),
"quantity" : 1,
"added_date" : ISODate("2015-09-05T20:32:16.527Z"),
"coupons" : ObjectId("55eb10cd516ddc751d3d5e25")
},
{
"item" : ObjectId("55eb10b8516ddc7508dba7c8"),
"quantity" : 1,
"added_date" : ISODate("2015-09-05T20:32:16.527Z"),
"coupons" : ObjectId("55eb10cd516ddc751d3d5e25")
}
]
}
Here are my models:
class CartItem(mongoengine.EmbeddedDocument):
item = mongoengine.ReferenceField('Item')
quantity = mongoengine.IntField()
added_date = mongoengine.DateTimeField( default=timezone.now() )
coupons = mongoengine.ReferenceField('Coupon')
order_type = mongoengine.ListField(mongoengine.StringField(choices=ORDER_TYPE_CHOICES))
class Cart(mongoengine.Document):
user = mongoengine.ReferenceField('User')
items = mongoengine.EmbeddedDocumentListField(CartItem)
savings = mongoengine.DecimalField(precision=2, default=0)
Now I want to be able to get CartItems that have for instance only order_type of "in_store". So I something like this:
cart = Cart.objects.filter(id="id")
items = cart.items
curbside_items = items.filter(order_type="curbside")
This does not return anything. So I try this:
curbside_items = items.filter(order_type__math="curbside")
But that does not return me anything as well.So my question is how can I do this in mongoengine.Thank You!
MongoEngine uses the "double underscore" for properties in translation to the "dot notation" form of MongoDB queries. So the "parent" of the property you are looking for is "items", which means you reference with the complete path like so:
Cart.objects.filter(items__order_type="in_store")
Where the document contains "in_store" as an order_type entry within the items array. Note that this returns "whole documents" and not just the matching entries. There are other ways to handle that in reponses.
One way is with a "raw" result using the underlying pymongo driver:
Cart._get_collection().find(
{ "items.order_type": "in_store" },
{ "items.$": 1 }
)
Which utilizes the positional $ operator in order to returned the matched array element only.
Or for "mutiple" matches then you need .aggregate():
Cart._get_collection().aggregate([
{ "$match": {
"items.order_type": "in_store"
}},
{ "$redact": {
"$cond": {
"if": { "$eq": [ { "$ifNull": [ "$order_type", "in_store" ] }, "in_store" ] },
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
Or making more sense in future releases via $filter:
Cart._get_collection().aggregate([
{ "$match": {
"items.order_type": "in_store"
}},
{ "$project": {
"items": {
"$filter": {
"input": "$items",
"as": "el",
"cond": { "$eq": [ "$$el.order_type", "in_store" ] }
}
}
}}
])
Standard mongoengine queries in the "djangoesque" line do not support such operations, and only return the whole document unmodifed. The exception is made for $slice where there is an option to do just what it's native MongoDB counterpart does as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With