Filter data with numbers groups

Hello dear Wix experts

I begin to use Velo and Wix Editor on a site which lists about 500 jigsaw puzzles. I have created a collection of puzzles, one of the fields is "numberOfPieces”, and this field is used as a filter in the repeater page which lists the puzzles.

For the moment I have created a dropdown menu in my page with all numbers of pieces registered in the database.

https://novyel.wixsite.com/website-5/liste

But the numbers of pieces are too precise and too disparate to have a correct filtering.

It would be much better to filter this field by range : under 200, then from 200 to 500, from 500 to 1000, etc…

What is the simplier way to make those ranges ? Do I have to build a backend javascript code ? Is it possible to add a computed field in my database ?

Thanks to give me any indication of how I can proceed.

No backend code needed, only frontend code is necessary for that

You can create a custom query like so:

wixData.query('yourCollection')
  .ge('pieces', minAmount)  // Greater than or Equal to
  .le('pieces', maxAmount)  // Less than or Equal to

Thank you Dean for your answer

So with that query I get all puzzles in one range.
But my purpose is to have several ranges and to list them in a kind of dropdown menu, so that the user choose a range and get all the puzzles of that range.

I have no idea of how to do that

The dropdown menu’s values should have the min/max pieces within them

Something like:

$w('#dropdown').options = [{
  label: '0 to 200', 
  value: '0,200'
}, {
  label: '200 to 500',
  value: '200,500'
}]

Then you can get the value selected using $w('#dropdown').value, and split the string to get the range

OK, I see, I try this and tell you, thank you very much

Terrific! It does work.

There is still a (light) issue.

When my page loads, the repeater display all the puzzles, and it takes 4 pages with about 350 puzzles.

Then I select the group according to the number of pieces, that’s OK, but at the bottom of the page, the index still appears even if the result of my query takes far less than one full page. And a click on an index displays puzzles with number of pieces out of range.

To illustrate what I try to explain, here is the URL of the page :
https://novyel.wixsite.com/website-5/liste
and here is my code :

import wixData from 'wix-data';

$w.onReady(function () {

    $w("#dynamicDataset").onReady(() => {

        $w('#dropdown3').onChange((event) => {
            let minNbPiece = Number(($w('#dropdown3').value).split("-")[0])
            let maxNbPiece = Number(($w('#dropdown3').value).split("-")[1])

            wixData.query("Properties")
                .ge("nombreDePices", minNbPiece)
                .le("nombreDePices", maxNbPiece)
                .ascending("nombreDePices")
                .find()
                .then(results => {

                    if (results.items.length > 0) {
                        let items = results.items;
                        $w('#listRepeater').data =
                            $w('#listRepeater').data = items

                    }
                })

        });

    });

});

Is #listRepeater connected to a dataset?
If so, that is probably the reason.

The pagination menu is linked to different pages on that dataset, so selecting one simply loads it, which refreshes the repeater with the original dataset configuration

Rather than querying the collection, and setting the repeater’s data to the result - filter the dataset already connected to your repeater:

$w('#dataset').setFilter(wixData.filter()
    .ge("nombreDePices", minNbPiece)
    .le("nombreDePices", maxNbPiece))

If you link your pagination bar and the repeater ( in the UI, don’t forget to set a high display limit)
to the same Dataset, then you can control them both by filtering the dataset via a dataset filter using the dropdown values.

$w.onReady(() => {
    $w("#dataset1").onReady(() => {
         
        $w('#dropdown1').onChange(() => {
            
            const [minNbPiece, maxNbPiece] = $w('#dropdown1').value.split("-").map(Number);

            //== Make a filter for the dataset
            const filter = wixData.filter()
                .ge("pieceCount", minNbPiece)
                .le("pieceCount", maxNbPiece);

            //== Set the  dataset to use filter 
            $w("#dataset1").setFilter(filter)
                .then(() => {
                    console.log("Success");
                })
                .catch(err => {
                    console.error("Error - Setting Filter:", err);
                });
        });
    });
});

As I come back to answer this post, I see @DeanAyalon , has posted a similar solution. That will teach me to be slow in setting up my test pages, :wink:

Thanks Dean and Mark, it works now, the pagination is OK. But… the query allowed me to sort my puzzles on the number of pieces, I don’t know how to do that with the setfilter function.
Is it possible to combine both sort and filter ?

I have set a limit of 100 elements to display in a page, does that answer to the question of Mark ?

Before you answer to me, I realize that there is another big issue: there are other way to filter the list in that page: filter on owner, on status, on tags,… Those filter are set without any coding, thanks to the features of wix. And they work perfectly together !
But this dropdown menu which allows to filter on the number of pieces doesn’t work with the others.
For instance, if I select the puzzles of daralinh (qui le gère), not available (non disponible), and then of 500 pieces, the puzzles of all people - available or not - of 500 pieces are listed.
I’m afraid I have to manage with a query for all criteria :cry:

True, because the code creates a new filter and sets the dataset to it, discarding whatever filter already exists - you can add whatever other query parameters you want to it in the code

As for the sorting, you can set it in the UI, in the dataset configuration

Understood, and thank you for your response.
It would have been much more simplier to have a computed field in my collection : when the puzzle is created, the owner enter the number of pieces, and the range is automatically filled in the computed field, so that I can manage it as the other fields.
Is that possible ?

Not sure I understood

Do you want a field in your CMS collection that, based on the pieces entered, resolves into the category described by the pieces range?

So that, when a puzzle is entered with 600 pieces for example, the range field would automatically populate with ‘500-1000’ for you to query as a single value?

If that is what you were thinking, then, yes, definitely possible.
You can use data hooks for that

OK, I am full of hope. I look at it and I tell you.

I have created a nice hook for the creation of a new puzzle.

export function Properties_beforeInsert(item, context) {
	if (item.nombreDePices >= 0 && item.nombreDePices < 201) 
    	item.range = 'moins de 200';
	if (item.nombreDePices >= 201 && item.nombreDePices < 401) 
    	item.range = 'de 200 à 400';
	if (item.nombreDePices >= 401 && item.nombreDePices < 751) 
    	item.range = 'autour de 500';
	if (item.nombreDePices >= 751 && item.nombreDePices < 1251) 
    	item.range = 'autour de 1000';
	if (item.nombreDePices >= 1251 && item.nombreDePices < 1751) 
    	item.range = 'autour de 1500';
 //etc...
    return item;
}

Is there a way to execute a batch job to fill the 350 puzzles yet registered ?

I only mentioned it because the default is 12. and originally was not 100% sure if you had connected via ui.

Yes, you can run a backend function that queries all items of a certain range, then updates them in bulk to the specified categories

When you export a backend function you can execute it right from the editor

Just, be careful, log the items to ensure you get the right ones, before you attempt to update them. Also, update a few before you do so for all of them

Another thing, you may want to change the before insert hook to fire whenever the data is changed. Unless you’re importing, you set the pieces field after the record was already inserted

1 Like

Thanks for the advices, I shall try a bit later, and tell you

I discovered a lot of interesting things thanks to Dean! hooks, beforeInsert, beforeUpdate.
Everything is working and even the bulk update wasn’t necessary, the range is automatically set if I put anything in the field in the CMS due to the beforeUpdate hook.
Here is the code of the hooks:

    if (item.nombreDePices >= 0 && item.nombreDePices < 201)
        item.range = '1) moins de 200';
    if (item.nombreDePices >= 201 && item.nombreDePices < 401)
        item.range = '2) de 200 à 400';
    if (item.nombreDePices >= 401 && item.nombreDePices < 751)
        item.range = '3) autour de 500';
    if (item.nombreDePices >= 751 && item.nombreDePices < 1251)
        item.range = '4) autour de 1000';
    if (item.nombreDePices >= 1251 && item.nombreDePices < 1751)
        item.range = '5) autour de 1500';
    if (item.nombreDePices >= 1751 && item.nombreDePices < 2501)
        item.range = '6) autour de 2000';
    if (item.nombreDePices >= 2501 && item.nombreDePices < 3201)
        item.range = '7) autour de 3000';
    if (item.nombreDePices >= 3201)
        item.range = '8) plus de 3200';

I had to add an index at the beginning of each value to display the ranges in the right order.

Thank you very much, you helped me so much!