node-collections-boilerplate-nahid/search/MongoSearch.js
/**
* @file
*
* @author Nahid Akbar
* @year 2016
* @copyright Data61 -
* Commonwealth Scientific and Industrial Research Organisation (CSIRO) -
* Australian Government. All rights reserved.
*/
"use strict";
const Search = require('./Search');
const MongoStorage = require('../storage/MongoStorage');
/**
* Search using mongodb query engine.
* Requres ```mongodb``` package.
*/
class MongoSearch extends Search
{
/**
* @override
*/
initialise(searchMeta, records)
{
const searchWeights = searchMeta.searchWeights || {};
let collection = this.collection;
return new Promise((resolve, reject) =>
{
function search()
{
let straight = {};
let text = {};
let textWeights = {};
for (let field in searchMeta.fields)
{
if (searchMeta.fields[field].dummy)
{
continue;
}
if (searchMeta.fields[field].searchField)
{
straight[searchMeta.fields[field].searchField] = 1;
}
else
{
straight[field] = 1;
}
if (searchMeta.fields[field].filters.indexOf('search') !== -1)
{
text[field] = 'text';
textWeights[field] = 1;
}
}
for (let field in searchWeights)
{
text[field] = 'text';
textWeights[field] = searchWeights[field];
}
let promises = [];
for (let field in straight)
{
let f = {};
f[field] = straight[field];
promises.push(collection.createIndex(f, {
background: true,
name: field + '_straight'
}));
}
console.log("INDEX", "TEXT", text, textWeights, "NORMAL", straight);
if (Object.keys(text)
.length > 0)
{
promises.push(collection.createIndex(text, {
background: true,
name: 'text',
weights: textWeights
}));
}
Promise.all(promises)
.then(resolve, reject);
}
//resolve();
collection.dropIndexes(() =>
{
collection.removeMany({}, () =>
{
if (records.length > 0)
{
collection.insertMany(records, {}, search);
}
else
{
search();
}
});
});
});
}
/**
* @override
*/
searchRecords(inquery, limit = 0)
{
const collection = this.collection;
const primaryKey = this.primaryKey;
return new Promise((resolve, reject) =>
{
let query = [],
f, hasTextSearch = false;
inquery.filter.forEach(infilter =>
{
switch (infilter.filter)
{
case 'equals':
f = {};
f[infilter.field] = infilter.value[0];
query.push(f);
break;
case 'within':
f = {};
f[infilter.field] = {
$in: infilter.value
};
query.push(f);
break;
case 'regex':
f = {};
f[infilter.field] = {
$regex: infilter.value[0]
};
query.push(f);
break;
case 'search':
hasTextSearch = true;
f = {
$text: {
$search: infilter.value[0],
$caseSensitive: false
}
};
query.push(f);
break;
default:
console.error('Unhandelled Filter', infilter);
}
});
if (query.length === 0)
{
query = {};
}
else if (query.length === 1)
{
query = query[0];
}
else
{
query = {
$and: query
};
}
let project = {
_id: 0
};
if (typeof primaryKey === 'string')
{
project[primaryKey] = 1;
}
else if (typeof primaryKey === 'object')
{
for (let key in primaryKey)
{
project[key] = 1;
}
}
let sort = {};
if (inquery.sort)
{
console.log(inquery.sort, hasTextSearch);
if (inquery.sort === 'search' && hasTextSearch)
{
project.score = {
$meta: "textScore"
};
sort.score = {
$meta: "textScore"
};
}
else
{
sort[inquery.sort] = inquery.order === 'dsc' ? -1 : 1;
}
}
console.log('MONGO QUERY', query, 'PROJECT', project, 'SORT', sort);
let search = collection.find(query)
.project(project)
.sort(sort);
if (limit)
{
search = search.limit(limit);
}
search.map(x => (typeof primaryKey === 'string') ? x[primaryKey] : x)
.toArray()
.then(resolve, reject);
});
}
// rest is the same as mongo storage
}
module.exports = MongoSearch;
MongoSearch.prototype.connect = MongoStorage.prototype.connect;
MongoSearch.prototype.createRecord = MongoStorage.prototype.createRecord;
MongoSearch.prototype.readRecord = MongoStorage.prototype.readRecord;
MongoSearch.prototype.updateRecord = MongoStorage.prototype.updateRecord;
MongoSearch.prototype.deleteRecord = MongoStorage.prototype.deleteRecord;