Multi-Select OR filtering behaviour

Hi, I have a data element that has a list of Tags in it. I then have a multi select box (using the bubble plugin for multi select) so a user can choose one or many tags.

Currently the filter is treating it like an “and” condition so the more tags you select the narrower the search result list is. The filter is using the “contains” argument (see picture).

I would like the opposite behaviour, so if a user selects two tags, it shows all elements containing either tag or both.

How can I achieve this?

1 Like

@sudsy thanks, that is very helpful.

From a quick read of the results it would seem like one side of the process is generally one element.

i.e. in your example reply the User seems to have one nationality compared against multiple search elements.

Or the search is one element and the data object has a list of things to look in.

That seems to be my understanding of the “is in” sort of mechanic.

Will it work with a list v list comparison?

As mentioned I will play around with the merged search as that seems more likely to work for my case but I thought I would jump start the conversation.

One warning on :merged
The performance becomes atrocious on high record count fetches. Depends on your data model, ordinality, and datatypes, but queries that generate roughly 1000/1500 records will time out on merge.

Forging a list from the checkboxes (via firing a workflow to compile the checked boxes into a list-type custom state, after every checkbox click or on the final action click), then performing an IS IN is preferable, and list contains list works as well as an non-inclusive conditional (ie it evaluates to true on (A,B) contains (B,C) in our use cases).

1 Like

Thanks, I understand what you are talking about however I am having trouble putting it into action.

My data has DealTags which is “list of text” which contains what I want to search against. When I then do the data source in the repeating group I am chosing “do a search” and picking Deal, then doing the constraint DealTags “contains” (it doesn’t give me any other option that makes sense) my custom built list of tags from clicking elements.

I have tried writing it the other way around but I can’t get the syntax to work at all.

The only time I have seen “is in” as an option the field is not a list so I don’t think that will work for me.

:confused:

Ok, so you want to constrain the list of returned objects to only those having tags which “overlap” with the tags chosen by the user. In Bubble logic, this could be implemented as a condition like…

ObjectList intersect with SelectedTags > 0

-Steve

Correct, in this case. CONTAINS should give you the correct result if ANY of the selected elements exists within your driver list (DealTags). In other words, true if (A,B) contains (B,C). This works in our use case.

This is outerbounds inclusive. Alternatively, if you wanted it innerbounds exclusive (ie only return results that when every single checked box exists in your driver set), you’d have to build the rule via DeMorgan’s law: your custom state list would consist of every checkbox NOT checked, then the constraint would be DealTags doesn’tcontain inverse_custom_state_list.

I know this is not your use case, just laying it here for FYI.

Steve is also correct, however this conditional can only implemented within a :filter after just performing a full DB unload with no constraints. This is fine for result sets in the hundreds of elements, but will show performance degradation on very large sets unless the capacity performance tier is bumped up commensurately.

I will have to try this out, maybe I have done something wrong but that is not how it is working for me. That is how I thought it would work but it seemed to only do full matching.

Hi Jesse,

Can you expound on that a bit? I understand that filters are applied after the original query, but why would the original query have to be unconstrained?

-Steve

Good to know!

Also, as a general FYI for new Bubblers, “search” is performed on the server and “filter” is performed client-side - that is, after the results of the search have been sent to the browser. Generally speaking, it’s best (more performant) to constrain the results with a search (server-side) as opposed to filtering the results after the data’s been retrieved.

-Steve

I didn’t think contains worked with two lists. I thought it works only with a list and a single item, both of which must be the same data type. Did you mean contains list?
 
 

If you are referring to the contains list operator, I don’t think this is correct. True will be returned only if all items in the second list are contained within the first. In the example you cite above, it would return false.

Perhaps I’m misunderstanding something. :confused:

-Steve

Can you expound on that a bit? I understand that filters are applied after the original query, but why would the original query have to be unconstrained?

Oh it doesn’t have to be generally. I was referring only to OP’s exact requirement, whereby the sole constraint would get yanked from the DB search and placed instead within a :filter to satisfy your suggestion.

This is our exact implementation in solving this. In this example, it’s checking if the proficient languages selected by a user match the languages spoken by another user. DB fetch is against list Sys_Speed_Total_Lang_List and is against custom state list Scan_State_Languages.

image

This is a “list contains list”, which returns true if there is AT LEAST one overlap.

EDIT: this discussion alone is proof more documentation needs to go in for the behavior of the various logical operators against different datatypes.

1 Like

Indeed! I actually tried with Text data types and it wouldn’t work, but maybe it depends on context as well. :thinking:

CORRECTION

In fact, I had not tried with a Text data type, but rather with a custom data type called “Tag” which had a single property called “Name” of type Text. I could not get Bubble to accept the “list contains list” expression when using a custom data type.

When I used the built-in Text data type instead of a custom data type, Bubble did accept the expression. However, I still can’t get it to behave as @anon38627393 describes. See further comments below.

Just to satisfy my burning curiosity, would you mind sharing a screenshot of the This Page’s Hobby_Scan_State_Languages custom state when you get a chance? (I mean a screenshot of its definition.) I think that would help me understand.

-Steve

Sure. It’s a vanilla list of texts.
image

Hey @anon38627393,

While I’ve gotten Bubble to accept the “list contains list” expression (by using the Text primitive data type), I’m not seeing the behavior you describe. I’m wondering if you can help me understand. Here’s my setup…

“Photos” data type having this field…

Custom state…

Search constraint…

No tags selected…

One tag selected…

Two tags selected…

 
 
In fact, any time more than one tag is selected, no results are returned at all. I’m a bit perplexed and hoping you can shed some light. Where am I going awry?

:confused:

-Steve

Very nice screenshot layout, a lot of the “dumb” pointers can be immediately ruled out just from looking at it. First up, you definitely have a problem more systemic than the behavior of the “contains” operator on list vs list. The give-away is the “That Place” element should’ve been returned even if “contains” was behaving exclusively instead of inclusively. The comparison isn’t working at all.

Would you mind sharing your workflow on SEARCH click? I’m shooting in the dark here, but I’d like to rule out a possible race condition that can be common with this.

@sudsy @anon38627393 wow thanks for the hard core discussion on this! I have to say I am in the same predicament as Steve, his photo example is exactly what I am struggling with.

I have attached my workflow, currently it is trying to do it direct but I get the same trying to use a custom state.

Aha!

I’m almost certain I understand what’s going on here now! What we are witnessing is Bubble’s automatic type conversion in action!

As I’ve noted in other posts, “Bubble will automatically convert a list of Text types into a comma-delimited string when that list is used in a string context.”

In fact, I’m leveraging this feature in this very test setup. The comma-separated tags in the Search Results RG is directly referencing an actual List object - the list of tags!


 
 
Therefore, what’s REALLY happening here…

…is that the “list of Texts” custom state (selected_tags) is actually being converted to a STRING (a Text data type in Bubble speak) - i.e. a comma-delimited string of tags - in order to satisfy the data type required in this context.

The observed behavior makes perfect sense in light of this, and it means that the contains operator does NOT work with two lists, but rather, it requires a single Text type for the comparison.

@anon38627393, I suggest you take another look at your filter implementation. At his point, I strongly suspect that the logic you’ve implemented is not actually working the way you think it is.

I’m really curious to hear your thoughts.

-Steve