Multi-Select OR filtering behaviour

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

You are correct. This was working fine in prod last year, and now it is not. Great. I’m glad we had this discussion and I’m sorry I was unwittingly misleading you.

I’m going to look at potential performant fixes, the only thing I can immediately come up with is a data model change to compress your list into an additional attribute on the table, space separated (via :join with). Then your query constraint can become

new_attribute CONTAINS KEYWORD(S) list-element

This is untested though and is only based on my understanding of contains-keywords behavior, that it will catch a true if at least one keyword is valid.

In the meantime, the :filtered application you suggested is the only remaining go-to, aside from :merge. in a variety of applications. Merge gets very brutal though with large sets.

2 Likes

If/when you implement this, please report back. I’d be curious to know how well it works.

-Steve

Thanks again for an enlightening discussion. For the moment I will rework my design :slight_smile:

1 Like

For posterity, the above mentioned theoretical design DOES NOT work.

EDIT: The only other (kind of wacky) way to keep it on DB is to:
-Assign a SELF_ID attribute to the table, that mimmics the Unique_ID column (needs to be manually set after every row creation everywhere in the app)
-Your DB constraint becomes
SELF_ID NOT IN ( Do A Search For TABLE’s SELF_ID, constraint table_list DOES NOT CONTAIN (search_filter_list))

This does the trick via DeMorgan’s law.

Other than that, rolling this back to :filter is the only other way to achieve the desired behavior.

1 Like