The following script might help you to detect changes between two layers having the same structure.
The algorithm works as follows:
- get a reference to layers to be compared
- write their common unique identifiers to a dict for faster access
- check if the new version has some identifiers not being in the set of old identifiers
- compare the other features having the same unique identifiers first by geometry, and if geometry is equal then on a field by field basis
- select all detected features on layer new
To write the selected features to a new layer "save layer as" with "selected only" option.
The script can be extended to report the differences found in more detail, eg. report wether geometry or attribute differ, and which attributes.
To run the script replace old_layer_name and new_layer_name in line 2-3, copy the code and paste it into Python console.
# get layers
old = QgsMapLayerRegistry.instance().mapLayersByName('old_layer_name')[0]
new = QgsMapLayerRegistry.instance().mapLayersByName('new_layer_name')[0]
# get the key field and feature id for faster access
old_feats = {feat['asset_id']:feat.id() for feat in old.getFeatures()}
new_feats = {feat['asset_id']:feat.id() for feat in new.getFeatures()}
# compare new fid with old fid; such fid being in the new set
# but not in the old represent new features
old_fid = set(old_feats.keys())
new_fid = set(new_feats.keys())
added_fid = new_fid.difference(old_fid)
# features added since old version
added_ids = [new_feats[fid] for fid in added_fid]
# features being in old AND new set
exist_fid = new_fid.difference(added_fid)
# get count of fields to compare
field_count = len(new.dataProvider().fields())
# list for changed features
changed_ids = []
# join the remainders by fid and compare them field by field
for fid in exist_fid:
old.setSelectedFeatures([old_feats[fid]])
new.setSelectedFeatures([new_feats[fid]])
old_feat = old.selectedFeatures()[0]
new_feat = new.selectedFeatures()[0]
# compare geometry and fields
if old_feat.geometry().equals(new_feat.geometry()):
for fi in range(field_count):
if old_feat[fi] != new_feat[fi]:
changed_ids.append(new_feats[fid])
break
else:
changed_ids.append(new_feats[fid])
# combine list of added and changed features
diff_ids = list(added_ids)
diff_ids.extend(changed_ids)
# select all different features
new.setSelectedFeatures(diff_ids)
# to simplify the process save new with selected only option to a result layer