3.5.8. Filtering data on a Topic

3.5.8.1. Creating a ContentFilteredTopic

A ContentFilteredTopic always belongs to a DomainParticipant. Creation of a ContentFilteredTopic is done with the create_contentfilteredtopic() member function on the DomainParticipant instance, that acts as a factory for the ContentFilteredTopic.

Mandatory arguments are:

  • A string with the name that identifies the ContentFilteredTopic.

  • The related Topic being filtered.

  • A string with the filter expression indicating the conditions for a sample to be returned.

  • A list of strings with the value of the parameters present on the filter expression.

Note

The number of parameter values cannot exceed the maximum set by the expression_parameters QoS configuration. The default (and absolute) maximum allowed as set by the OMG DDS Standard is 100.

Optional arguments are:

  • A string with the name of the filter class to use for the filter creation. This allows the user to create filters different from the standard SQL like one (please refer to Using custom filters). Defaults to FASTDDS_SQLFILTER_NAME (DDSSQL).

Important

Setting an empty string as filter expression results in the disabling of the filtering. This can be used to enable/disable the DataReader filtering capabilities at any given time by simply updating the filter expression.

create_contentfilteredtopic() will return a null pointer if there was an error during the operation, e.g. if the related Topic belongs to a different DomainParticipant, a Topic with the same name already exists, syntax errors on the filter expression, or missing parameter values. It is advisable to check that the returned value is a valid pointer.

Note

Different filter classes may impose different requirements on the related Topic, the expression, or the parameters. The default filter class, in particular, requires that a TypeObject for the related Topic’s type has been registered. When using fastddsgen the TypeObject registration code is generated by default.

// Create a DomainParticipant in the desired domain
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant)
{
    // Error
    return;
}

// Create the Topic.
/* IDL
 *
 * struct HelloWorld
 * {
 *     long index;
 *     string message;
 * }
 *
 */
Topic* topic =
        participant->create_topic("HelloWorldTopic", "HelloWorld", TOPIC_QOS_DEFAULT);
if (nullptr == topic)
{
    // Error
    return;
}

// Create a ContentFilteredTopic using an expression with no parameters
std::string expression = "message like 'Hello*'";
std::vector<std::string> parameters;
ContentFilteredTopic* filter_topic =
        participant->create_contentfilteredtopic("HelloWorldFilteredTopic1", topic, expression, parameters);
if (nullptr == filter_topic)
{
    // Error
    return;
}

// Create a ContentFilteredTopic using an expression with parameters
expression = "message like %0 or index > %1";
parameters.push_back("'*world*'");
parameters.push_back("20");
ContentFilteredTopic* filter_topic_with_parameters =
        participant->create_contentfilteredtopic("HelloWorldFilteredTopic2", topic, expression, parameters);
if (nullptr == filter_topic_with_parameters)
{
    // Error
    return;
}

// The ContentFilteredTopic instances can then be used to create DataReader objects.
Subscriber* subscriber =
        participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
if (nullptr == subscriber)
{
    // Error
    return;
}

DataReader* reader_on_filter = subscriber->create_datareader(filter_topic, DATAREADER_QOS_DEFAULT);
if (nullptr == reader_on_filter)
{
    // Error
    return;
}

DataReader* reader_on_filter_with_parameters =
        subscriber->create_datareader(filter_topic_with_parameters, DATAREADER_QOS_DEFAULT);
if (nullptr == reader_on_filter_with_parameters)
{
    // Error
    return;
}

3.5.8.2. Updating the filter expression and parameters

A ContentFilteredTopic provides several member functions for the management of the filter expression and the expression parameters:

// This lambda prints all the information of a ContentFilteredTopic
auto print_filter_info = [](
    const ContentFilteredTopic* filter_topic)
        {
            std::cout << "ContentFilteredTopic info for '" << filter_topic->get_name() << "':" << std::endl;
            std::cout << "  - Related Topic: " << filter_topic->get_related_topic()->get_name() << std::endl;
            std::cout << "  - Expression:    " << filter_topic->get_filter_expression() << std::endl;
            std::cout << "  - Parameters:" << std::endl;

            std::vector<std::string> parameters;
            filter_topic->get_expression_parameters(parameters);
            size_t i = 0;
            for (const std::string& parameter : parameters)
            {
                std::cout << "    " << i++ << ": " << parameter << std::endl;
            }
        };

// Create a DomainParticipant in the desired domain
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant)
{
    // Error
    return;
}

// Create a Topic
/* IDL
 *
 * struct HelloWorld
 * {
 *     long index;
 *     string message;
 * }
 *
 */
Topic* topic =
        participant->create_topic("HelloWorldTopic", "HelloWorldTopic", TOPIC_QOS_DEFAULT);
if (nullptr == topic)
{
    // Error
    return;
}

// Create a ContentFilteredTopic
ContentFilteredTopic* filter_topic =
        participant->create_contentfilteredtopic("HelloWorldFilteredTopic", topic, "index > 10", {});
if (nullptr == filter_topic)
{
    // Error
    return;
}

// Print the information
print_filter_info(filter_topic);

// Use the ContentFilteredTopic on DataReader objects.
// (...)

// Update the expression
if (RETCODE_OK !=
        filter_topic->set_filter_expression("message like %0 or index > %1", {"'Hello*'", "15"}))
{
    // Error
    return;
}

// Print the updated information
print_filter_info(filter_topic);

// Update the parameters
if (RETCODE_OK !=
        filter_topic->set_expression_parameters({"'*world*'", "222"}))
{
    // Error
    return;
}

// Print the updated information
print_filter_info(filter_topic);

3.5.8.3. Deleting a ContentFilteredTopic

A ContentFilteredTopic can be deleted with the delete_contentfilteredtopic() member function on the DomainParticipant instance where the ContentFilteredTopic was created.

// Create a DomainParticipant in the desired domain
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant)
{
    // Error
    return;
}

// Create a Topic
/* IDL
 *
 * struct HelloWorld
 * {
 *     long index;
 *     string message;
 * }
 *
 */
Topic* topic =
        participant->create_topic("HelloWorldTopic", "HelloWorldTopic", TOPIC_QOS_DEFAULT);
if (nullptr == topic)
{
    // Error
    return;
}

// Create a ContentFilteredTopic
ContentFilteredTopic* filter_topic =
        participant->create_contentfilteredtopic("HelloWorldFilteredTopic", topic, "index > 10", {});
if (nullptr == filter_topic)
{
    // Error
    return;
}

// Use the ContentFilteredTopic on DataReader objects.
// (...)

// Delete the ContentFilteredTopic
if (RETCODE_OK != participant->delete_contentfilteredtopic(filter_topic))
{
    // Error
    return;
}