简体   繁体   中英

How to count products to multiple filters separated by group

I like to make counter for product filters like this one Online Shop , when you select any filter/option from GROUP X to count/update products into other GROUPS->filters/options but not in the current one

for example if this is frontend filters checkboxes

Size (group_id: 33)
  10m (option_id: 52) (21 products)
  20m (option_id: 51) (1 product)

Color (group_id: 32)
  Green (option_id: 49) (22 products)
  Black (option_id: 38) (1 product)

We are looking for result only from one category_id 127

Example of same group check counting

If option_id: 52 checked

    Size (group_id: 33)
[x] 10m (option_id: 52) (21 products)
  20m (option_id: 51) (1 product)

Color (group_id: 32)
  Green (option_id: 49) (22 products)
  Black (option_id: 38) (1 product)

Result:

option_id:38    0,
option_id:49    2,
option_id:51    1,
option_id:52    21

option_id:51 and 52 still have initial state

If option_id: 51 checked

 Size (group_id: 33)
  10m (option_id: 52) (21 products)
[x]  20m (option_id: 51) (1 product)

Color (group_id: 32)
  Green (option_id: 49) (22 products)
  Black (option_id: 38) (1 product)

Result:

38  0
49  1
51  1
52  21

option_id:51 and 52 still have initial state

Example of different group check counting

Size (group_id: 33)
[x]  10m (option_id: 52) (21 products)
  20m (option_id: 51) (1 product)

Color (group_id: 32)
[x] Green (option_id: 49) (22 products)
  Black (option_id: 38) (1 product)

Result:

38  0
49  2
51  1
52  2

all option should become updated and lose their initial state

When you select one or more option_id from same group_id logic of showing products will be

for example: show products with size 10m and show products with 20m

if you select option_id:51 first it should not update option_id:52 becasue they are in same group but will update all option_id in group_id: 32 and so on

When you select option_id from different group_id logic of showing products will be

for example: show products with size 10m who also have color green (if is available)

@Akina has done most of the code for counting in this Topic

Working example of DB and Query

SELECT options.option_id,
   COUNT(DISTINCT CASE WHEN filter_counter.option_id = options.option_id 
                       THEN product_id 
                       END) option_count
FROM filter_counter
CROSS JOIN ( SELECT DISTINCT option_id
         FROM filter_counter ) options
JOIN ( SELECT DISTINCT product_id
   FROM filter_counter
   WHERE option_id IN (51) ) filter1 USING (product_id)
GROUP BY options.option_id;



      CREATE TABLE `filter_counter` (
      `id` int(11) NOT NULL,
      `group_id` int(11) NOT NULL,
      `option_id` int(11) NOT NULL,
      `product_id` int(11) NOT NULL,
      `category_id` int(11) NOT NULL,
      `manufacturer_id` int(11) NOT NULL
      ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

    INSERT INTO `filter_counter` (`id`, `group_id`, `option_id`, `product_id`, `category_id`, `manufacturer_id`) VALUES
    (1, 33, 52, 5124, 65, 36),
    (2, 33, 52, 5124, 127, 36),
    (3, 33, 52, 5125, 65, 36),
    (4, 33, 52, 5125, 127, 36),
    (5, 33, 52, 5138, 65, 36),
    (6, 33, 52, 5138, 127, 36),
    (7, 33, 52, 5141, 65, 36),
    (8, 33, 52, 5141, 127, 36),
    (9, 33, 52, 5146, 65, 36),
    (10, 33, 52, 5146, 127, 36),
    (11, 33, 52, 5147, 65, 36),
    (12, 33, 52, 5147, 127, 36),
    (13, 33, 52, 5148, 65, 36),
    (14, 33, 52, 5148, 127, 36),
    (15, 33, 52, 5149, 65, 36),
    (16, 33, 52, 5149, 127, 36),
    (17, 33, 52, 5150, 65, 36),
    (18, 33, 52, 5150, 127, 36),
    (19, 33, 52, 5151, 65, 36),
    (20, 33, 52, 5151, 127, 36),
    (21, 33, 52, 5152, 65, 36),
    (22, 33, 52, 5152, 127, 36),
    (23, 33, 52, 5153, 65, 36),
    (24, 33, 52, 5153, 127, 36),
    (25, 33, 52, 5154, 65, 36),
    (26, 33, 52, 5154, 127, 36),
    (27, 33, 52, 5155, 65, 36),
    (28, 33, 52, 5155, 127, 36),
    (29, 33, 52, 5156, 65, 36),
    (30, 33, 52, 5156, 127, 36),
    (31, 33, 52, 5157, 65, 36),
    (32, 33, 52, 5157, 127, 36),
    (33, 33, 52, 7042, 65, 38),
    (34, 33, 52, 7042, 127, 38),
    (35, 33, 52, 7048, 65, 38),
    (36, 33, 52, 7048, 127, 38),
    (37, 33, 52, 7124, 65, 0),
    (38, 33, 52, 7124, 127, 0),
    (39, 32, 49, 7185, 65, 0),
    (40, 32, 49, 7185, 127, 0),
    (41, 32, 49, 7517, 65, 39),
    (42, 32, 49, 7517, 127, 39),
    (43, 32, 49, 7518, 65, 39),
    (44, 32, 49, 7518, 127, 39),
    (45, 32, 49, 7538, 65, 39),
    (46, 32, 49, 7538, 127, 39),
    (47, 32, 49, 7657, 65, 39),
    (48, 32, 49, 7657, 127, 39),
    (49, 32, 49, 7658, 65, 39),
    (50, 32, 49, 7658, 127, 39),
    (51, 32, 49, 7797, 65, 21),
    (52, 32, 49, 7797, 127, 21),
    (53, 32, 49, 7798, 65, 21),
    (54, 32, 49, 7798, 127, 21),
    (55, 32, 49, 7799, 65, 21),
    (56, 32, 49, 7799, 127, 21),
    (57, 32, 49, 7800, 65, 21),
    (58, 32, 49, 7800, 127, 21),
    (59, 32, 49, 7801, 65, 21),
    (60, 32, 49, 7801, 127, 21),
    (61, 32, 49, 7802, 65, 21),
    (62, 32, 49, 7802, 127, 21),
    (63, 32, 49, 7803, 65, 21),
    (64, 32, 49, 7803, 127, 21),
    (65, 32, 49, 7804, 65, 21),
    (66, 32, 49, 7804, 127, 21),
    (67, 32, 49, 7805, 65, 21),
    (68, 32, 49, 7805, 127, 21),
    (69, 32, 49, 7806, 65, 21),
    (70, 32, 49, 7806, 127, 21),
    (71, 32, 49, 7807, 65, 21),
    (72, 32, 49, 7807, 127, 21),
    (73, 32, 49, 7808, 65, 21),
    (74, 32, 49, 7808, 127, 21),
    (75, 32, 49, 7809, 65, 21),
    (76, 32, 49, 7809, 127, 21),
    (77, 32, 49, 7810, 65, 21),
    (78, 32, 49, 7810, 127, 21),
    (79, 32, 38, 7811, 65, 21),
    (80, 32, 38, 7811, 127, 21),
    (81, 32, 49, 8020, 65, 21),
    (82, 32, 49, 8020, 127, 21),
    (83, 33, 52, 8020, 65, 21),
    (84, 33, 52, 8020, 127, 21),
    (85, 32, 49, 8021, 65, 21),
    (86, 32, 49, 8021, 127, 21),
    (87, 33, 51, 8021, 65, 21),
    (88, 33, 51, 8021, 127, 21),
    (89, 33, 52, 8021, 65, 21),
    (90, 33, 52, 8021, 127, 21);

(What is the "question"?)

I think the best way to implement such is to build a query based on the checkboxes, then process the data in a single pass in your application language.

Side issue: Switch from MyISAM to InnoDB.

Side issue: Shrink INT (which takes 4 bytes) to smaller datatypes.

The point behind these side issues is performance and space. Many of the generated queries will involve a full table scan, filtering as it goes. (That is, INDEXes will not be useful much of the time.)

The user can click multiple boxes in each grouping, correct? Then consider having, for example, TINYINT UNSIGNED , which has 8 bits (in 1 byte) to handle up all combinations of up to 8 choices. For example, instead of

AND size_id IN (0, 1)   -- 0 means '65in+'; 1 means '50-65in'

do

AND ((size_opts & 0x3) = 0x3)

That is, the bottom bit of size_opts represents '65in+', etc.

This would shrink the dataset quite a bit and require different pre-processing to generate the queries.

Note that the value of your size_id is 0..4, my size_opts would have some or all of the bottom 5 bits on.

ORing together (1 << size_id) values gets you from size_id to size_opts .

(More)

There are 2 things going on:

  • Filtering (limiting the display by brand/price/color/whatever)
  • Counting how many are still in the running (by each remaining criteria)

To goals are needed to make it somewhat efficient:

  • Shrink the dataset as much as possible
  • Don't include in the table any items that are 'deleted' etc. Don't include any columns that are not relevant to the filtering and counting. They fight with the shrinkage goal
  • Shrink the categorization as much as possible. The "bit fiddling" I suggested may be optimal.
  • Build the query dynamically. Leave out unnecessary tests. (Example: When nothing is clicked for Brand, don't test for Brand.)
  • To rephrase, build a table just for this purpose. Focus on it; ignore all other aspects of the data. Even if the data in this table is redundant, you must optimize this table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM