It is generally a bad idea to use the empty string as a target property. You could rewrite that binding as:
new Binding('visible', '', data => filteredModel.nodes.indexOf(data.key) >= 0)
And as the documentation points out it is inefficient to use the empty string as a source property, although sometimes it is unavoidable. It is particularly inefficient that your binding is calling Array.indexOf so frequently.
But, it would be better not to use a Binding for this at all, as well as not calling rebuildParts. Instead, only when the value of filteredModel.nodes has changed, then within a single transaction I would create a Set of those filtered keys and then iterate over all of the Diagram.nodes and set each Node.visible to whether the Node.key is contained in that Set.
// if filteredModel.nodes has changed:
myDiagram.commit(function(diag) {
var filteredKeys = new go.Set(filteredModel.nodes);
diag.nodes.each(function(n) { n.visible = filteredKeys.has(n.key); });
}, "updated filter");