我正在使用 MongoEngine 创建一个查询,该查询仅返回与约束匹配的车辆。如您所见,Vehicle 是一个 EmbeddedDocument,Owner 是父文档。我的查询是使用Q,查询结果不同,只匹配本田品牌和元素型号的车辆。
from mongoengine.queryset.visitor import Q
def get_vehicles():
vehicles = json.loads(Owner.objects(Q(vehicle__brand='Honda') and Q(vehicle__model='Element')).only('vehicle').to_json())
return {"vehicles":vehicles}
class Vehicle(engine.EmbeddedDocument):
model = engine.StringField(required=True, max_length=50)
brand = engine.StringField(required=True, max_length=100)
plates = engine.StringField(required=True, max_length=50)
year = engine.IntField(required=True)
color = engine.StringField(required=True, max_length=80)
type = engine.StringField(required=True, max_length=80)
subtype = engine.StringField(required=True, max_length=80)
doors = engine.IntField(required=True)
transmission = engine.StringField(required=True, max_length=80)
photos = engine.ListField(engine.StringField(max_length=150))
equipment = engine.ListField(engine.StringField(max_length=80))
powered_by = engine.StringField(required=True, max_length=80)
availability = engine.ListField(engine.DateField())
pickup_place = engine.PointField()
creation_date = engine.DateTimeField(required=True)
class Owner(engine.Document):
_id = engine.ObjectIdField()
name = engine.StringField(required=True, max_length=100)
surname = engine.StringField(required=True, max_length=100)
gender = engine.StringField(required=True, max_length=1)
birthday = engine.DateField(required=True)
creation_date = engine.DateTimeField(required=True)
last_update = engine.DateTimeField()
photo = engine.StringField(required=True, max_length=200)
access = engine.EmbeddedDocumentField(Access)
address = engine.EmbeddedDocumentField(Address)
vehicle = engine.EmbeddedDocumentListField(Vehicle)
答案 0 :(得分:0)
实际上,您正在查询父集合 (Owner),因此查询会返回所有所有者文档,其中包含与您的 Q 条件匹配的任何车辆。
虽然不优雅,但在 Python 中添加第二个过滤通道可以解决问题:
from mongoengine import *
connect()
class Vehicle(EmbeddedDocument):
model = StringField(required=True, max_length=50)
brand = StringField(required=True, max_length=100)
def __repr__(self):
return f'Vehicle({self.brand} - {self.model})'
class Owner(Document):
vehicles = EmbeddedDocumentListField(Vehicle)
Owner(vehicles=[Vehicle(model="Civic", brand="Honda"), Vehicle(model="Element", brand="Honda")]).save()
Owner(vehicles=[Vehicle(model="Golf", brand="VW")]).save()
def get_vehicles(brand, model):
matched_owners = Owner.objects(Q(vehicles__brand=brand) and Q(vehicles__model=model)).only('vehicles')
vehicles = [vehicle for owner in matched_owners for vehicle in owner.vehicles if vehicle.brand == brand and vehicle.model == model]
return vehicles
get_vehicles("Honda", "Element") # Print [Vehicle(Honda - Element)]
您想要的使用聚合管道可能是可行的,但如果您的用例真的是这个,那么您就可以了
题外话,但我建议您避免定义“_id”属性,MongoEngine 默认为您提供一个 id = ObjectIdField()
字段并在内部使用“_id”属性,因此覆盖它不是一个好主意(主要MongoEngine 贡献者在这里)
答案 1 :(得分:0)
我接近我想要的结果,但我需要将结果添加到车主 ID 中。
def get_vehicles():
matched_owners = json.loads(Owner.objects(Q(vehicle__brand='VW') and Q(vehicle__model='Jetta')).only('vehicle').to_json())
vehicles = [ vehicle for owner in matched_owners for vehicle in owner['vehicle'] if vehicle['brand'] == "VW" and vehicle['model'] == "Jetta"]
return {"vehicles":vehicles}
与我想要的结果匹配的 Mongo shell 查询是:
db.owner.find({"vehicle.brand":"VW"},{vehicle:{$elemMatch:{model:"Jetta"}}});
答案 2 :(得分:0)
我在 MongoShell 上得到了我想要的结果
db.owner.aggregate([{ $unwind:"$vehicle"}, {$match:{ "vehicle.model":"Jetta", "vehicle.brand":"VW"}}, {$project: {"vehicle.model":1, "vehicle.brand":1, "vehicle.color":1, "vehicle.doors":1, "vehicle.transmission":1, "vehicle.powered_by":1 ,"vehicle.photos":1, "vehicle.equipment":1, "vehicle.availability":1, "vehicle.pickup_place":1}} ]);```
i attempted to do the same on MongoEngine, but the result is different:
```python
def get_vehicles():
pipeline = [
{ "$unwind":"$vehicle"},
{
"$match":{ "vehicle.model":"Jetta", "vehicle.brand":"VW"}
},
{
"$project": {"vehicle.model":1, "vehicle.brand":1, "vehicle.color":1, "vehicle.doors":1, "vehicle.transmission":1, "vehicle.powered_by":1 ,"vehicle.photos":1, "vehicle.equipment":1, "vehicle.availability":1, "vehicle.pickup_place":1}
}
]
vehicles = Owner.objects.aggregate(pipeline)
return {"vehicles":vehicles}```