Skip to content

Instantly share code, notes, and snippets.

@russll

russll/search.js Secret

Last active March 31, 2017 11:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save russll/6bb06e91a7fc1dad6755085ccb48afdf to your computer and use it in GitHub Desktop.
Save russll/6bb06e91a7fc1dad6755085ccb48afdf to your computer and use it in GitHub Desktop.
Логика обработчика поиска
'use strict';
const config = require('nconf');
const R = require('ramda');
const webApi = require('../../api/web');
const searchApi = require('../../api/search');
const sanitize = require('../../helpers/sanitizeSearchQuery');
const esConfig = config.get('es');
module.exports = function *getSearch() {
const defaultOptions = {
types: ['questions', 'tags', 'places'],
fields: ['attributes.title', 'attributes.text', 'attributes.synonyms'],
query: '',
project: 1,
limit: esConfig.limit
};
const webApiEnabled = this.state.filter.api;
const types = this.state.filter.type &&
(Array.isArray(this.state.filter.type) ? this.state.filter.type : [this.state.filter.type]);
const fields = this.state.filter.fields &&
(Array.isArray(this.state.filter.fields) ? this.state.filter.fields : [this.state.filter.fields]);
const inputOptions = {};
/* eslint-disable curly */
if (this.state.filter.q) inputOptions.query = this.state.filter.q;
if (this.state.page.limit) inputOptions.limit = this.state.page.limit;
if (this.query.project) inputOptions.project = this.query.project;
if (types) inputOptions.types = types;
if (fields) inputOptions.fields = fields;
/* eslint-enable curly */
const elasticsearchOptions = Object.assign({}, defaultOptions, inputOptions);
let webApiPlaces = [];
if (webApiEnabled && elasticsearchOptions.types.indexOf('places') != -1) {
webApiPlaces = yield searchWebApiPlaces(elasticsearchOptions.project, elasticsearchOptions.query, elasticsearchOptions.limit);
}
const searchResult = yield searchApi.msearch(elasticsearchOptions)
.then(body => body.responses.reduce((acc, item, index) => {
const type = elasticsearchOptions.types[index];
if (type == 'places' && webApiEnabled) {
const apiId = checkItem => {
if (checkItem._source) {
return R.path(['_source', 'attributes', 'apiId'], checkItem);
}
return R.path(['attributes', 'apiId'], checkItem);
};
const preparePlaces = R.pipe(
R.concat,
R.uniqBy(apiId),
R.take(elasticsearchOptions.limit)
);
return acc.concat(preparePlaces(item.hits.hits, webApiPlaces));
}
return acc.concat(item.hits.hits);
}, []))
.catch(err => {
if (this.log) {
this.log.error(err);
}
});
if (!searchResult) {
this.throw(404, 'Ничего не найдено');
}
this.body = {
data: searchResult.map(item => {
if (item._source) {
item._source._id = item._id;
return item._source;
}
return item;
})
};
};
function *searchWebApiPlaces(project, q, limit) {
const webapiItemsMap = new Map([
['adm_div.city', 'city'],
['adm_div.settlement', 'settlement'],
['adm_div.division', 'division'],
['adm_div.district', 'district'],
['adm_div.living_area', 'livingArea'],
['adm_div.place', 'place'],
['station', 'station'],
['station.metro', 'metro'],
['crossroad', 'crossroad'],
['address', 'address'],
['building', 'building'],
['attraction', 'attraction']
]);
const sanitezedQ = sanitize(q);
const convertToSquareFormat = item => ({ // Приводим к формату сквера
attributes: {
title: titleCase(item.hint.text),
apiId: item.hint.id,
placeType: webapiItemsMap.get(item.hint.hint_type)
},
type: 'apiPlace'
});
const apiRequest = webApi.getSuggests(project, sanitezedQ, limit)
.then(R.map(convertToSquareFormat));
return yield Promise.resolve(apiRequest);
}
function titleCase(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment