Although you're asking for an answer related to value map combo-boxes, I thought to provide an alternative where you could use the following code to read the values in the first row for each column and copy it for each of the attributes. Select the layer in QGIS and copy/paste the code into the Python Console (Plugins -> Python Console
or Ctrl + Alt + P):
layer = qgis.utils.iface.activeLayer()
layer.startEditing()
for field in layer.pendingFields():
name = field.name()
request = QgsFeatureRequest().setFilterFid(0)
feat = layer.getFeatures(request).next()
result = feat[name]
for feature in layer.getFeatures():
feature[name] = result
layer.updateFeature(feature)
This is not automated, which is what you seem to be asking for. But I hope it helps a little anyway! Tested this on QGIS 2.8.2-Wien.
Update:
If you want to run the above script in the graphical modeler, first select the Create new script tool from Processing Toolbox -> Scripts
. Note you said 7 columns but gave 8 :). Then insert the following:
##Copy attributes from first row=name
##Layer=vector
import qgis
from qgis.core import *
layer = processing.getObject(input)
layer.startEditing()
for field in layer.pendingFields():
name = field.name()
request = QgsFeatureRequest().setFilterFid(0)
feat = layer.getFeatures(request).next()
result = feat[name]
for feature in layer.getFeatures():
if name == 'ALT_0':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_1':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_2':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_3':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_4':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_5':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_Ideale':
feature[name] = result
layer.updateFeature(feature)
if name == 'ALT_propos':
feature[name] = result
layer.updateFeature(feature)
Also note that I purposely did not save the changes just incase there's a mistake. If you want the script to save the changes, use the layer.commitChanges()
code at the end of the script outside all the for
loops.
I tested this and it seems to work so hopefully it will for you too =)
Note that if "idTargetLayer"
in mySourceLayer
already is an array, you need to remove string_to_array()
for this field, see comment by OP below.
Option 1 - Independent "ID", but more complex expression
If your IDs are numerical but have nothing to do with the featureIDs of the layer, you can use this, a little more complex, expression:
array_to_string(
array_foreach(
array_foreach(
array_foreach(
string_to_array("idTargetLayer",', '),to_int(@element)), -- create an integer array of the values to search for
array_find(
array_foreach(
aggregate('myTargetLayer','array_agg',"idTargetLayer" || '|' ||"myField"), -- create an array of the IDs and myField values, intended to work similar to a Python-Dictionary, | is the unique separator between key and value
regexp_substr(@element,'[0-9]*')), -- extract the IDs of this 'Dictionary'
@element -- get the index of the value we will extract later
)
),
array_get(
array_foreach(
aggregate('myTargetLayer','array_agg',"idTargetLayer" || '|' ||"myField"), -- create an array of the IDs and myField values, intended to work similar to a Python-Dictionary, | is the unique separator between key and value
regexp_substr(@element,'[0-9][|](.*)')), -- extract the Values of this 'Dictionary'
@element) -- get the current integer array element of the value dict
),
',')
Its a little hard to explain, and even confusing myself, but I hope you get the idea of it. However, as the result shows, its working fine:
Option 2 - "ID" is related to layers featureID and easier expression
The following expression should work if the id
's of myTargetLayer
are the layer's featureID
's:
array_to_string(
array_foreach(
array_foreach(
string_to_array("idTargetLayer"), -- idTargetLayer is a string so we need to convert it to an array first
to_int(@element)), -- idTargetLayer is a string field, so we need to convert the numbers to integer before we can look it up
attributes(get_feature_by_id('myTargetLayer',@element))['myField'] -- get the attribute of ['myfield'] of the layer 'myTargetLayer' for the featureID '@element', where @element is the extracted integer of 'idTargetLayer' array
)
,',') -- convert the gathered array back to a string
Best Answer
Try using this expression (QGIS 3.22) in the 'Filter expression' part of your Value Relation widget -
It groups the feature id value from the other layer by the desired column, then just grabs the feature with the first id value from that list. The list is therefore filtered to just the first instance of each
"culture"
value. It's similar to the 'first value' aggregate that is present in several languages/tools, I'm not sure if Q 3.24 has introduced this as its own function.I'm not sure if it will be very efficient if the source table is quite large though.
Example:
If you know your source layer will be updated regularly/dynamically,
$id
(QGIS interpreted feature id) can be a little unpredictable (esp with unsaved features), so instead of using$id
in the above expression, you could also use a column from the source layer that you know will be unique and non-null every time a new feature is created (e.g."uuid"
or"id"
)