-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
79 lines (70 loc) · 2.27 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
const nlp = require('wink-nlp-utils');
const { isFunction } = require('./utils');
const PREFIX = '__nGramTextSearch_';
const toNGrams = (str, nGramSizeMin, nGramSizeMax) => {
const result = [];
for (let i = nGramSizeMin; i <= nGramSizeMax; i += 1) {
result.push(...nlp.string.ngrams(str, i));
}
return result;
};
module.exports = function (schema, options) {
const { fields = [], nGramSizeMin = 2, nGramSizeMax = 3, fieldPrefix = PREFIX } = options;
const getNGramField = name => `${fieldPrefix}_${name}`;
const textIndex = {};
fields.forEach((fieldOpt) => {
const {
name,
} = fieldOpt;
const fieldType = schema.path(name);
if (!fieldType || fieldType.instance !== 'String') {
throw new Error('Only accept fields with type String');
}
schema.add({
[getNGramField(name)]: { type: String },
});
textIndex[getNGramField(name)] = 'text';
textIndex[name] = 'text';
});
schema.index(textIndex, { default_language: 'none', name: PREFIX });
schema.pre('save', function (next) {
fields.forEach((fieldOpt) => {
const {
name, extractFn,
} = fieldOpt;
const fieldName = getNGramField(name);
const value = isFunction(extractFn) ? extractFn(this[name]) : this[name];
if (value) {
this[fieldName] = toNGrams(value, nGramSizeMin, nGramSizeMax).join(' ');
} else {
this[fieldName] = '';
}
});
next();
});
const updateHookHandler = function (next) {
if (!this.getUpdate().$set) {
this.getUpdate().$set = {}
}
fields.forEach((fieldOpt) => {
const {
name, extractFn,
} = fieldOpt;
const fieldName = getNGramField(name);
const getter = key => this.getUpdate().$set[key] || this.getUpdate()[key];
const setter = (key, value) => this.getUpdate().$set[key] = value;
const updatedValue = getter(name)
if (updatedValue) {
const value = isFunction(extractFn) ? extractFn(updatedValue) : updatedValue;
if (value) {
setter(fieldName, toNGrams(value, nGramSizeMin, nGramSizeMax).join(' '));
} else {
setter(fieldName, '');
}
}
});
next();
};
schema.pre('findOneAndUpdate', updateHookHandler);
schema.pre('updateOne', updateHookHandler);
};