Поиск в таблице по нескольким столбцам с помощью React, Node.js и Mongo - PullRequest
0 голосов
/ 03 августа 2020

Есть таблица с несколькими столбцами, и теперь можно искать столбец. Когда текст вводится в поле поиска, выполняется фильтр, и отображаются только строки, содержащие это слово в этом столбце.

Например, есть 3 столбца: имя , бренд , продажи . Поиск ведется по столбцу имя . Я хочу, чтобы он выполнял поиск по всем столбцам, но не знаю, как это сделать.

Вот как это работает сейчас.

Файл реакции:

import React from 'react';
import { connect } from 'react-redux';
import { Creators } from '../../../actions';
import Layout from '../../../components/Layout/Layout';
import ContentContainer from '../../../components/Layout/ContentContainer';
import GenericTable from '../../../components/Table/GenericTable';
import OneColumn from '../../../components/Layout/OneColumn';
import SearchBox from '../../../components/SearchBox/SearchBox.component';
import TabContainer from '../../../components/Layout/TabContainer';

class Products extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      query: {
        name: '',
        brand: '',
        sales: '',
      },
    };
  }

  componentDidMount() {
    const { getProducts, getProviders } = this.props;
    getProducts(this.state.query);
    getProviders();
  }

  searchHandler = event => { // here is the search function 
    const { getProducts } = this.props;
    getProducts({
      name: event.target.value, // it works for only for name column now
      brand: this.props.query.brand,
      sales: this.props.query.sales,
    });
  };

  render() {
    const listHeaders = ['ID', 'Name', 'Brand', 'Sales'];

    const listTab = (
      <ContentContainer>
        <div>
          <div>
            <SearchBox
              placeholder="Search product"
              onChange={this.searchHandler} // here is the search box
            />
          </div>
          <GenericTable // the table 
            id="products-table"
            headers={listHeaders}
            rows={listRows}
            entityName="products"
            idList={listIdList}
          />
        </div>
      </ContentContainer>
    );

    return (
      <Layout>
        <OneColumn>
          <TabContainer>
            <Tab.Pane>{listTab}</Tab.Pane>
          </TabContainer>
        </OneColumn>
      </Layout>
    );
  }
}

const mapStateToProps = state => ({
  products: state.products.products,
  query: state.products.query,
});

const mapDispatchToProps = {
  getProducts: Creators.getProductsRequest,
};

export default connect(mapStateToProps, mapDispatchToProps)(Products);

запрос построен с помощью redux-saga:

const api = API.create();

export function* getProducts({ query }) {
  let urlQuery = '';
  if (query && query.name) {
    urlQuery += `&name=${query.name}`;
  }

  if (query && query.brand) {
    urlQuery += `&brand=${query.brand}`;
  }

  if (query && query.sales) {
    urlQuery += `&price=${query.sales}`;
  }

  try {
    const response = yield call(api.getProducts, urlQuery);
    yield put(Creators.getProductsSuccess(response.data));
  } catch (error) {
    yield put(Creators.getProductsFailure(error));
  }
}

В Node.js есть 3 метода для 3 вариантов поиска, возможно, их нужно объединить в один, но не знаю как:

findAll: (req, res) => {
    const aggregateOptions = [];
  
       // search by name
       if (req.query.name) {
        aggregateOptions.push({ $match: { name: { $regex: req.query.name, $options: 'i' } } });
      }
  
      // search by brand
      if (req.query.brand) {
        aggregateOptions.push({ $match: { brand: { $regex: req.query.brand, $options: 'i' } } });
      }
  
      // search by sales
      if (req.query.sales) {
        aggregateOptions.push({ $match: { brand: { $regex: req.query.sales, $options: 'i' } } });
      }

    aggregateOptions.push({
      $project: {
        productId: 1,
        name: 1,
        brand: 1,
        sales: 1,
      },
    });

    const myAggregate = Product.aggregate(aggregateOptions);
    Product.aggregatePaginate(myAggregate, options)
      .then(function(results) {
        return res.send(results);
      })
      .catch(function(err) {
        return res.status(400).send({ message: err.message });
      });
  }

Итак, когда я пишу «s» в поле поиска, это вызов API: http://localhost:5000/products&name=s.

Я не знаю, можно ли сделать что-то вроде http://localhost:5000/products&name=s || brand=s || sales=s или как это можно сделать для поиска из одного окна поиска по всем 3 столбцам.

1 Ответ

0 голосов
/ 03 августа 2020

Перед вызовом getProducts в обработчике поиска необходимо вызвать setState и обновить состояние. Что касается того, о чем вы спрашивали, у меня есть решение, требующее некоторого рефакторинга, вы можете установить состояние {query: ''}, чтобы фильтровать только текст, и вы отправляете его на бэкэнд, где вы выполняете поиск в базе данных (вы ищете фильтр запроса текст в первом столбце, затем во втором, затем в третьем и pu sh все результаты в один и тот же массив.

EDITED для саги о сокращении

const api = API.create();

export function* getProducts({ query }) {
    let urlQuery = '';
    if(query){
        urlQuery += `&query=${query}`;
    }


    try {
        const response = yield call(api.getProducts, urlQuery);
        yield put(Creators.getProductsSuccess(response.data));
    } catch (error) {
        yield put(Creators.getProductsFailure(error));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...