-
Notifications
You must be signed in to change notification settings - Fork 75
Description
Due to an existing data model setup in PostgreSQL, we received a request to add support for N-M relations.
In QGIS, N-M relations are implemented on top of the existing 1-N relation system. When configured correctly, QGIS adjusts the feature form UI so that the intermediate association table is hidden from the user.
Parent (1) ------ (N) Association/Join table (N) ------- (1) Child
This behaviour is controlled by the Cardinality setting in the feature form. When the relations are configured as shown above, QGIS recognises the N-M pattern and skips the association table in the UI.
As a result, users see a simplified interface where one parent feature can have multiple children, and a single child can be associated with multiple parents, without interacting with the linking table directly:
| Parent view | Child view |
|---|---|
Mergin Maps side of things
The same general approach used in QGIS could be implemented in Mergin Maps. In other words, the parent form’s relation widget would list features from the child layer directly - and the child layer would list its parents - while the association (join) table remains hidden from the UI.
At the moment, our mobile app hides the relation widget entirely whenever it detects an N-M setup. This happens on both the parent and child layers:
This behaviour is intentional:
mobile/app/attributes/attributecontroller.cpp
Lines 306 to 312 in 0c7071e
| bool isNmRelation = layer->editFormConfig().widgetConfig( associatedRelation.id() )[QStringLiteral( "nm-rel" )].toBool(); | |
| if ( isNmRelation ) | |
| { | |
| CoreUtils::log( "Relations", QStringLiteral( "Nm relations are not supported in layer %1" ).arg( layer->name() ) ); | |
| continue; | |
| } | |
To support N-M relations properly, the main change required is to adjust how we fetch related features from the referenced (child) layer.
Currently, RelationFeaturesModel retrieves related features like this:
mobile/app/relationfeaturesmodel.cpp
Line 64 in 0c7071e
| QgsFeatureRequest e = mRelation.getRelatedFeaturesRequest( mParentFeatureLayerPair.feature() ); |
With N-M relations, the first call to getRelatedFeaturesRequest returns features from the association table, not directly from the child layer. Therefore, for each returned association-table feature, we need to perform an additional lookup - calling getRelatedFeaturesRequest (or the filter version) again - to retrieve the corresponding child features.
By merging these second-level results, we obtain the final list of child features to display in the relation widget. Essentially:
- Fetch rows from the association table.
- For each row, resolve the referenced child feature.
- Combine the results into a single list for the UI.
It is a bit more work under the hood, but conceptually straightforward - and it would allow us to support N-M relations in a way consistent with QGIS.
For example, this is how it is done in QGIS: https://github.com/qgis/QGIS/blob/c755c5864983ce5cbb7f47b22cbea17ff5a9bc75/src/gui/qgsrelationeditorwidget.cpp#L624-L650
You can find a demo project with n-m relations setup here: https://app.dev.merginmaps.com/projects/SurveyCorp/many-to-many-relation/tree
Next steps (to explore)
- We need to figure out how to support adding new child/parent features (check QGIS code)
- What to do if parent/child feature is removed (anything to do in the association table?), a bit related to Relationship strength "composite" has no effect in the app #2315