我想让 MongoEngine Query 只返回我想要的车辆,但它不起作用

时间:2021-06-28 18:44:59

标签: mongodb mongoengine fastapi

我正在使用 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)

3 个答案:

答案 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}```