Skip to content

Store the ifcJSON in the Database

Feature Group: Store | PostgreSQL

This is done by reading the ifcJSON, loading it in pandas DataFrame and or Series and splitting it in categories.

  • Representations
  • PropertySets
  • Relationships
  • Objects: all entities that are not in one of the 3 others

Thereafter, there is a basic processing to adjust to the Physical model which is under /src/model/common.py with SQLModel / Pydantic definitions.

Submit the processing request

#
# Store an IFCJSON in the database
#
class StoreIfcJsonInDb_Instruction(BaseModel):
    spatialUnitId: str | None = "5f2d17b0-43fb-445d-9c67-7dafb3292c33"
    bundleName: str | None = "Duplex_A_20110907_optimized" # name of the bundle
    sourceFileURL: str | None = "http://localhost:8002/IFCJSON/7be56a97-3db3-4c85-94e8-86ac45b63ff6_FIL.json" 
    parentBundleId: str | None = None # remove this if there is no parent

class StoreIfcJsonInDb_Result(BaseModel):
    bundleId: str    
    runtime: float | None = 0.0 # in seconds

In the Instruction:

  • the spatialUnitId is the id of the spatialUnit associated to the IfcJSON file and to the corresponding IFC; - to be stored in the database, an association of the IfcJSON to a SpatialUnit is mandatory. This one can be created with the corresponding service.
  • the bundleName is the name for the bundle that will logically contain the data of the IfcJSON; the choice of the name is free
  • the sourceFileURL is that of the IfcJSON file
  • the parentBundleId is that if the parent bundle when there is one

In the Result:

  • the bundleId is the string value of the bundle integer id

Object Table in the database

The physical model is available under /src/model/common.py with SQLModel / Pydantic definitions.

Hereunder the example of the object table.

class object(SQLModel, table=True):
    bundle_id: int = Field(nullable=False, alias='bundleId', primary_key=True)
    object_id: UUID4 = Field(primary_key=True)
    type: str = Field(nullable=False)
    name: str = Field(nullable=True) # have object with no name (e.g. IfcOpeningElement)
    representation_ids: list[str] = Field(sa_column=Column(ARRAY(String(36))), default=[], alias='representationIds')
    elementjson: dict = Field(sa_column=Column(JSON), default={}, alias='elementJson')
    created_at: datetime.datetime = Field(sa_column=Column(DateTime(), default=func.now(), nullable=False))
    updated_at: Optional[datetime.datetime] = Field(sa_column=Column(DateTime(), nullable=True ))
  • The object_id is the IFC globalId in expanded format as provided by IFC2JSON.
  • The type is the IfcEntity Name (IfcProject, IfcSite, IfcBuilding, IfcBuildingStorey, ...). It could be replaced by a shorter id (e.g. int).
  • The name is the name provided in the IFC. In principle it should bear some meaning, but that is not always the case. In some IFC, it may just not provided.
  • The representation_ids (list / array) are the ids of the representations (geometries). They are extracted from the entity json to be available for queries
  • The ifcjson is the copy of the entity dictionary provided by ifcJSON. It is not exploded and can be processed as needed by a specific use case.

The other tables follow the same pattern. It is worth noting that FastAPI/ SQLModel/SQLAlchemy can create all tables that where not already there on startup of the server (or when needed).

The database is PostgreSQL. For this upload, bulk inserts are used, following the guidelines of Fastest-Methods-to-Bulk-Insert-Pandas-Dataframe-into-PostgreSQL using psycopg2 copy_expert()

Complement the bundle data

The database is updated with:

  • an entry in the bundle table
  • an entry in the bundleJournal table
  • an entry in the bundleUnit as a root entity (the project)
  • an entry in the spatialUnitBundleUnit table
flowchart TB
    bundle
    bundleJournal
    spatialUnit["spatial=Unit: root"]
    bundleUnit["bundleUnit: root"]
    spatialUnitBundleUnit
    spatialUnitBundleUnit --o bundleUnit
    spatialUnitBundleUnit --o spatialUnit
    bundle --o bundleUnit
    bundle --o bundleJournal
    bundleUnit --o bundleUnitSite["bundleUnit: site"]
    bundleUnitSite --o bundleUnitBuilding["bundleUnit: building"]
    bundleUnitBuilding --o bundleUnitStorey["bundleUnit: storey"] 
    bundleUnitStorey --o bundleUnitSpace["bundleUnit: space"]