Как реализовать логику фильтра?

Есть три выпадающих списка. Нужно сделать так, чтобы фильтровало по всем параметрам списка.


adsRouter.get('/', async (req,res) => {
  const city = req.query.city;
  const price = req.query.price;
  const date = req.query.date;
  const category = req.query.category
  const sectionParams = req.query.section
  const subsectionParams = req.query.subsection
  const page = req.query.page;
  const pagesize = 25;

  const reqQuery = {
    city: city,
    category: category,
    section: sectionParams,
    subsection: subsectionParams,
    price: price,
    date: date,
  };

  const query = [
    {
      $match: {}
    },
    {
      $addFields: {
        __order: { $indexOfArray: [Reference.Status, '$status'] }
      }
    },
    {
      $sort: {
        __order: 1,
        ...(reqQuery.price ? { productPrice: reqQuery.price === 'high' ? -1 : 1 } : {}),
        ...(reqQuery.date ? { backendDate: reqQuery.date === 'high' ? -1 : 1 } : {}),
        updatedAt: -1
      }
    },
    { $skip: ((page || 1) - 1) * pagesize },
    { $limit: pagesize }
  ];
  if (reqQuery.city) {
    query[0].$match.city = { $eq: reqQuery.city };
  }
  if (reqQuery.category) {
    query[0].$match.category = { $eq: reqQuery.category };
  }
  if (reqQuery.section) {
    query[0].$match.section = { $eq: reqQuery.section };
  }
  if (reqQuery.subsection) {
    query[0].$match.subsection = { $eq: reqQuery.subsection };
  }

  const items = await AdModel.aggregate(query);
  const arr = await AdModel.find({category: category})
  const pages = _.chunk(arr, pagesize).length 
  
  res.json([items,pages])
})

введите сюда описание изображения


Ответы (1 шт):

Автор решения: nörbörnën

Делаем тестовую модель

// @ts-check
const mongoose = require('mongoose');
const { Schema } = require('mongoose');

const Status = ['gold', 'silver', 'common'];
const Cities = ['Moscow', 'London', 'Paris'];
const Categories = ['Coffee', 'Tea'];
const Sections = ['One', 'Two'];
const Subsections = ['Four', 'Five'];

const schema = new Schema(
  {
    productPrice: { type: Number, required: true },
    backendDate: { type: Date, required: true },
    status: { type: String, enum: Status, required: true },
    city: { type: String, enum: Cities, required: true },
    category: { type: String, enum: Categories, required: true },
    section: { type: String, enum: Sections, required: true },
    subsection: { type: String, enum: Subsections, required: true },
  },
  {
    timestamps: true,
    autoIndex: true,
    autoCreate: true
  }
);

module.exports = {
  Reference: {
    Status,
    Cities,
    Categories,
    Sections,
    Subsections,
  },
  AdModel: mongoose.model('AdModel', schema)
};

Делаем тестовую заливку данных

const mongoose = require('mongoose');
const { AdModel, Reference } = require('./model');

(async () => {
  try {
    await mongoose.connect(
      'mongodb://localhost:27017/test?readPreference=primary&appname=MongoDB%20Compass%20Community&ssl=false',
      { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true }
    );

    AdModel.collection.drop();

    let count = 1000;
    while (--count >= 0) {
      await AdModel.create({
        productPrice: randomNumber(1000000),
        backendDate: randomDate(),
        status: Reference.Status[randomNumber(Reference.Status.length)],
        city: Reference.Cities[randomNumber(Reference.Cities.length)],
        category: Reference.Categories[randomNumber(Reference.Categories.length)],
        section: Reference.Sections[randomNumber(Reference.Sections.length)],
        subsection: Reference.Subsections[randomNumber(Reference.Subsections.length)],
      });
    }

    await mongoose.disconnect();
  } catch (err) {
    console.error(err);
  }
})();

/**
 * @param {number} min
 * @param {number} [max]
 * @returns {number}
 */
function randomNumber(min = 0, max) {
  if (max === null || max === undefined) {
    max = min; min = 0;
  }
  return Math.trunc(Math.random() * (max - min) + min);
}

function randomDate(start = new Date(2000, 0, 1), end = new Date()) {
  return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
}

Забираем все данные одним запросом

// @ts-check
const mongoose = require('mongoose');
const { AdModel, Reference } = require('./model');

(async () => {
  try {
    await mongoose.connect(
      'mongodb://localhost:27017/test?readPreference=primary&appname=MongoDB%20Compass%20Community&ssl=false',
      { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true }
    );

    const reqQuery = {
      city: Reference.Cities[0],
      subsection: Reference.Subsections[0],
      price: 'high',
      date: 'high',
    };

    const page = randomNumber(10);

    const pagesize = 25;

    const query = [
      {
        $match: {}
      },
      {
        $addFields: {
          __order: { $indexOfArray: [Reference.Status, '$status'] }
        }
      },
      {
        $sort: {
          __order: 1,
          ...(reqQuery.price ? { productPrice: reqQuery.price === 'high' ? -1 : 1 } : {}),
          ...(reqQuery.date ? { backendDate: reqQuery.date === 'high' ? -1 : 1 } : {}),
          updatedAt: -1
        }
      },
      { $skip: ((page || 1) - 1) * pagesize },
      { $limit: pagesize }
    ];
    if (reqQuery.city) {
      query[0].$match.city = { $eq: reqQuery.city };
    }
    if (reqQuery.category) {
      query[0].$match.category = { $eq: reqQuery.category };
    }
    if (reqQuery.section) {
      query[0].$match.section = { $eq: reqQuery.section };
    }
    if (reqQuery.subsection) {
      query[0].$match.subsection = { $eq: reqQuery.subsection };
    }

    const items = await AdModel.aggregate(query);
    console.log(items);
    console.log(items.length);


    await mongoose.disconnect();
  } catch (err) {
    console.error(err);
  }
})();

Есть вещи, которые я никогда не смогу понять, одна из них - использование mongodb (я бы мог добавить "там, где её лучше не использовать", но нет).

→ Ссылка