0

Recently I stuck on inserting an element into an array that held by a parent document. Basically, my model represents a train that can have many wagons. The wagons is an array that hold a wagon.

Here is my database model

rom typing import Optional,Union

from pydantic import BaseModel, EmailStr, Field

#Wagon Model
class Wagon(BaseModel):
    no: int = Field(...)
    wagon_code: str = Field(...)
    wagon_type: str = Field(...)
    passengers_on_board: int = Field(...)
    max_capacity: int = Field(...)
    weight: float = Field(...)
    dimension: tuple  = Field(...)

    class Config:
        schema_extra = {
            "example": {
                "no": 3,
                "wagon_code": "GA151-03",
                "wagon_type": "Penumpang",
                "passengers_on_board": 40,
                "max_capacity":80,
                "weight":1050.01,
                "dimension": (20.62,9.91,4.15)
            }
        }

class UpdateWagon(BaseModel):
    no: Optional[int] 
    wagon_code: Optional[str]
    wagon_type: Optional[str]
    passengers_on_board: Optional[int]
    max_capacity: Optional[int]
    weight: Optional[float]
    dimension: Optional[tuple]
    
    class Config:
        schema_extra = {
            "example": {
                "no": 3,
                "wagon_code": "GA151-03",
                "wagon_type": "Penumpang",
                "passengers_on_board": 64,
                "max_capacity":80,
                "weight":1050.01,
                "dimension": (20.62,9.91,4.15)
            }
        }


#Train Model
class Train(BaseModel):
    name: str = Field(...)
    no: str = Field(...)
    first_station: str = Field(...)
    last_station: str = Field(...)
    from_: str = Field(...)
    to_: str = Field(...)
    current_station: str = Field(...)
    position: Optional[tuple]
    wagons: Union[list[Wagon], None] = None

    class Config:
        schema_extra = {
            "example": {
                "name": "Gajayana",
                "no": "GA-151",
                "first_station": "Malang - Kota Baru",
                "last_station": "Jakarta - Gambir",
                "from_":"Malang - Kota Baru",
                "to_":"Malang - Kota Lama",
                "current_station":"Malang - Kota Baru",
                "position": (2.12,2.12),
                "wagons" : [],
                }
        }

class UpdateTrain(BaseModel):
    name: Optional[str]
    no: Optional[str]
    first_station: Optional[str]
    last_station: Optional[str]
    from_: Optional[str]
    to_: Optional[str]
    current_station: Optional[str]
    position: Optional[tuple]
    wagons: Optional[list]

    class Config:
        schema_extra = {
            "example": {
                "name": "Gajayana",
                "no": "GA-151",
                "first_station": "Malang - Kota Baru",
                "last_station": "Jakarta - Gambir",
                "from_":"Malang - Kota Lama",
                "to_":"Kepanjen",
                "current_station":"Malang - Kota Baru",
                "position": (2.08,2.16),
                "wagons": [],
            }
        }

I was using arrayFilters to attach the newly created wagon to the train. However, I got no luck to attach the model but a new wagon was created as shown in the function below.

async def add_wagon(train_no: str,wagon_data: dict) -> dict:
    wagon = await wagon_collection.insert_one(wagon_data)
    new_wagon = await wagon_collection.find_one({"_id": wagon.inserted_id})
    train = await train_collection.find_one({"no": train_no})
    if train:
        train_collection.update_one({"no": train_no},{"$set":{"wagons.$[element]":new_wagon}},array_filters=[{"element":{"$exists":"false"}}],upsert=True)
    return wagon_helper(new_wagon)

The model was served as an API with FASTAPI. The operation above was done using PUT method with the route as shown below.

@router.put("{train_no}/wagons/", response_description="Wagon data added into the database")
async def add_wagon_data(train_no: str,wagon: Wagon = Body(...)):
    wagon = jsonable_encoder(wagon)
    new_wagon = await add_wagon(train_no,wagon)
    return ResponseModel(new_wagon, "Wagon added successfully")

Is my arrayFilters is wrong ? or is the way I use $exists as exact equality match is incorrect ?

1
  • 1
    array_filters update option is for updating a specific array element (and $push update operator is for adding new element(s) to an array). Commented Jun 1, 2022 at 5:55

1 Answer 1

0

It turns out I was thinking too complicated. USing $push with upsert=True solve the problem.

async def add_wagon(train_no: str,wagon_data: dict) -> dict:
    wagon = await wagon_collection.insert_one(wagon_data)
    new_wagon = await wagon_collection.find_one({"_id": wagon.inserted_id})
    train = await train_collection.find_one({"no": train_no})
    if train:
        train_collection.update_one({"no": train_no},{"$push":{"wagons":new_wagon}},upsert=True)
    return wagon_helper(new_wagon)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.