Dynamic relatedTo queries I've got an advanced search form which culminates in:

craft.entries.section('whatsOn').relatedTo(
    'and',
    { element: artCategories },
    { element: locationCategories },
    { element: bbfcCategories }
).search(searchTerm).order('score').limit(8)


This works, but only if the item being searched for has populated artCategories, locationCategories, and bbfcCategories.

Any of those are optional; i.e., the bbfcCategories line may not be needed at all... and likewise the searchTerm - is there a way to do this dynamically?
You can build the array for your criteria model's relatedTo parameter step for step before adding it:

{# Initial criteria model #}
{% set exhibitions = craft.entries.section('exhibitions').limit(null) %}

{# Compose relatedTo parameter #}
{% set relatedToParam = ['and'] %}

{% if query.art is defined %}
    {% set catIds = craft.categories.group('artCategories').id(query.art).ids() %}
    {% set relatedToParam = relatedToParam|merge([{ targetElement: catIds }]) %}
{% endif %}

{% if query.location is defined %}
    {% set catIds = craft.categories.group('locationCategories').id(query.location).ids() %}
    {% set relatedToParam = relatedToParam|merge([{ targetElement: catIds }]) %}
{% endif %}

{# Add additional criteria. Avoid passing an array with 'and' only #}
{% if relatedToParam|length &gt; 1 %}
    {% set exhibitions = exhibitions.relatedTo(relatedToParam) %}
{% endif %}