After some brain matter reducing thinking with ChatGPT, I’ve finally found the most efficient expression to check if a list field of a record has been updated in a backend workflow.
Basically, we compare the count of old and new lists when merged versus the count of the same lists when intersected.
A simple expression to use in the backend. I use it to compare when a list field of a Record has changed in a DB trigger. This is the most accurate and simplest method so far. No need for Bubble to do additional processing of list or filters.
Works in any conditional if you need to compare 2 lists that don’t match. Originally, I built a plugin to compare lists on the frontend - Definitely overkill for something simple.
Don’t ask how it works. My brain needs to recover. I’ve tested in my sandbox, will test it in prod soon. Do give me feedback if you’ve found edge cases.
Another way is List A:format as text is not List B:format as text where inside format as text you have the unique ID (if thing) or the content (if option set/something else).
If in backend trigger, you can use List A:each item's unique id join with , is not List B:each item's unique id join with , which is basically the same
In a train to an errand so I got some brain back. My lists are pretty small so either works. You got me thinking about comparing large lists, more than 50 records.
A hash of all the UIDs stored as a field will be much more efficient in the long run.
Hey @ihsanzainal84, it’s great that you reasoned it out. You’re spot on. The only suggestion I would make is to use is not instead of >. That way, either merged or intersection can come first in the expression and one needn’t concern themselves with the direction of the angle bracket. The fact that there’s a count difference is all that matters. It simply indicates the lists are different.
Lists merged:count is not List intersection:count
What’s more, there’s simple logic to determine exactly which items were added and/or removed:
Get the list of items removed
List before:minus list (List intersection)
Get the list of items added
List now:minus list (List Intersection)
I do exactly this in one of my apps. Users can have multiple roles, and I use a DB trigger to execute some logic whenever there’s a change to a user’s roles. I also send an admin notification with the user’s current roles as well as exactly which roles were added/removed.
For anyone interested in learning more, this all has to do with the mathematics of “finite sets”. In Bubble, “merged” is what’s known as a set “union”. An LLM can take it from there.
Just be mindful of sort order, as this approach is nondeterministic with respect to list content alone. That is, it will produce a different output even if the items comprising the list don’t change but their order does.
For example, if the app has logic which overwrites the original list with a reordered copy, such as…
ListItems set list = This Thing's ListItems:sorted by Field
or
ListItems set list = RG's List of ListItems (where RG is sorted)
…then that would result in a modification where the content of the list doesn’t change but the order does.
Of course, it’s easy to account for that by simply sorting each list before formatting as text…
List A:sorted by uid each item's uid join with , is not List B:sorted by uid each item's uid join with ,
This delimited string comparison approach has the advantage of being able to detect a change in order only.
Either content or order has changed (unsorted list before !== unsorted list after)
Only content has changed (sorted list before !== sorted list after)
Only the order has changed (sorted list before === sorted list after AND unsorted list before !== unsorted list after)
If you’re not concerned with the order of items, working directly with lists allows you to determine not just that the lists are different but how they are different.
I did think about it but because I’m not really sure how Bubble processes is not. Integers are faster comparators versus strings. So I couldn’t come to a conclusion to what would require less processing on the backend.
In the end I decided to go with a MD5 Hash as a single field. Waay simpler expression and most of the processing (looking at this specific feature of “looking for updates to the list”) done clientside.
Since the comparison is between two integers, I’d be really surprised if Bubble did a type conversion to a string. I suspect it’s using a strict inequality operator under the hood - e.g. int1 !== int2.
Anyway, glad you got it working to your satisfaction.