nodebb-plugin-dbsearch 5.0.3 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +1 -137
- package/lib/dbsearch.js +530 -516
- package/lib/mongo.js +114 -115
- package/lib/postgres.js +111 -111
- package/lib/redis.js +52 -52
- package/package.json +5 -5
- package/plugin.json +2 -5
- package/public/.eslintrc +3 -0
- package/{lib → public}/admin.js +120 -124
- package/{public/templates → templates}/admin/plugins/dbsearch.tpl +0 -0
- package/upgrades/dbsearch_change_mongodb_schema.js +11 -32
package/lib/mongo.js
CHANGED
|
@@ -1,115 +1,114 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const nconf = require.main.require('nconf');
|
|
4
|
-
|
|
5
|
-
const db = require.main.require('./src/database');
|
|
6
|
-
|
|
7
|
-
exports.createIndices = async function (language) {
|
|
8
|
-
const options = { background: true };
|
|
9
|
-
if (language && language !== 'en') {
|
|
10
|
-
options.default_language = language;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (nconf.get('isPrimary') && !nconf.get('jobsDisabled')) {
|
|
14
|
-
await db.client.collection('searchtopic').createIndex({ content: 'text', uid: 1, cid: 1 }, options);
|
|
15
|
-
await db.client.collection('searchpost').createIndex({ content: 'text', uid: 1, cid: 1 }, options);
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
exports.changeIndexLanguage = async function (language) {
|
|
20
|
-
const indexSpec = { content: 'text', uid: 1, cid: 1 };
|
|
21
|
-
const options = { background: true };
|
|
22
|
-
if (language !== 'en') {
|
|
23
|
-
options.default_language = language;
|
|
24
|
-
}
|
|
25
|
-
await db.client.collection('searchtopic').dropIndex('content_text_uid_1_cid_1');
|
|
26
|
-
await db.client.collection('searchtopic').createIndex(indexSpec, options);
|
|
27
|
-
await db.client.collection('searchpost').dropIndex('content_text_uid_1_cid_1');
|
|
28
|
-
await db.client.collection('searchpost').createIndex(indexSpec, options);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
exports.searchIndex = async function (key, data, ids) {
|
|
32
|
-
if (!ids.length) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
ids = ids.map(id => parseInt(id, 10));
|
|
37
|
-
|
|
38
|
-
const bulk = db.client.collection(
|
|
39
|
-
ids.forEach(
|
|
40
|
-
const setData = {};
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
aggregate.push({ $
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const nconf = require.main.require('nconf');
|
|
4
|
+
|
|
5
|
+
const db = require.main.require('./src/database');
|
|
6
|
+
|
|
7
|
+
exports.createIndices = async function (language) {
|
|
8
|
+
const options = { background: true };
|
|
9
|
+
if (language && language !== 'en') {
|
|
10
|
+
options.default_language = language;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (nconf.get('isPrimary') && !nconf.get('jobsDisabled')) {
|
|
14
|
+
await db.client.collection('searchtopic').createIndex({ content: 'text', uid: 1, cid: 1 }, options);
|
|
15
|
+
await db.client.collection('searchpost').createIndex({ content: 'text', uid: 1, cid: 1 }, options);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
exports.changeIndexLanguage = async function (language) {
|
|
20
|
+
const indexSpec = { content: 'text', uid: 1, cid: 1 };
|
|
21
|
+
const options = { background: true };
|
|
22
|
+
if (language !== 'en') {
|
|
23
|
+
options.default_language = language;
|
|
24
|
+
}
|
|
25
|
+
await db.client.collection('searchtopic').dropIndex('content_text_uid_1_cid_1');
|
|
26
|
+
await db.client.collection('searchtopic').createIndex(indexSpec, options);
|
|
27
|
+
await db.client.collection('searchpost').dropIndex('content_text_uid_1_cid_1');
|
|
28
|
+
await db.client.collection('searchpost').createIndex(indexSpec, options);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
exports.searchIndex = async function (key, data, ids) {
|
|
32
|
+
if (!ids.length) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ids = ids.map(id => parseInt(id, 10));
|
|
37
|
+
|
|
38
|
+
const bulk = db.client.collection(`search${key}`).initializeUnorderedBulkOp();
|
|
39
|
+
ids.forEach((id, index) => {
|
|
40
|
+
const setData = {};
|
|
41
|
+
Object.keys(data[index]).forEach((field) => {
|
|
42
|
+
if (data[index].hasOwnProperty(field) && data[index][field]) {
|
|
43
|
+
setData[field] = data[index][field].toString();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
bulk.find({ _id: id }).upsert().updateOne({ $set: setData });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await bulk.execute();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
exports.search = async function (key, data, limit) {
|
|
54
|
+
const searchQuery = {};
|
|
55
|
+
if (data.content) {
|
|
56
|
+
let words = data.content.split(' ');
|
|
57
|
+
const allQuoted = data.content.startsWith('"') && data.content.endsWith('"');
|
|
58
|
+
if (data.matchWords === 'all' && !allQuoted) {
|
|
59
|
+
words = words.map((word) => {
|
|
60
|
+
if (!word.startsWith('"') && !word.endsWith('"')) {
|
|
61
|
+
return `"${word}"`;
|
|
62
|
+
}
|
|
63
|
+
return word;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
searchQuery.$text = { $search: words.join(' ') };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (Array.isArray(data.cid) && data.cid.length) {
|
|
71
|
+
if (data.cid.length > 1) {
|
|
72
|
+
searchQuery.cid = { $in: data.cid.map(String) };
|
|
73
|
+
} else {
|
|
74
|
+
searchQuery.cid = String(data.cid[0]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(data.uid) && data.uid.length) {
|
|
79
|
+
if (data.uid.length > 1) {
|
|
80
|
+
searchQuery.uid = { $in: data.uid.map(String) };
|
|
81
|
+
} else {
|
|
82
|
+
searchQuery.uid = String(data.uid[0]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const aggregate = [{ $match: searchQuery }];
|
|
87
|
+
if (searchQuery.$text) {
|
|
88
|
+
const sortQuery = { score: { $meta: 'textScore' } };
|
|
89
|
+
if (data.searchData.sortBy === 'timestamp' || data.searchData.sortBy === 'topic.timestamp') {
|
|
90
|
+
sortQuery._id = data.searchData.sortDirection === 'asc' ? 1 : -1;
|
|
91
|
+
}
|
|
92
|
+
aggregate.push({ $sort: sortQuery });
|
|
93
|
+
} else {
|
|
94
|
+
aggregate.push({ $sort: { _id: data.searchData.sortDirection === 'asc' ? 1 : -1 } });
|
|
95
|
+
}
|
|
96
|
+
aggregate.push({ $limit: parseInt(limit, 10) });
|
|
97
|
+
aggregate.push({ $project: { _id: 1 } });
|
|
98
|
+
|
|
99
|
+
const results = await db.client.collection(`search${key}`).aggregate(aggregate).toArray();
|
|
100
|
+
if (!results || !results.length) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
return results.map(item => item._id);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
exports.searchRemove = async function (key, ids) {
|
|
107
|
+
if (!key || !ids.length) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
ids = ids.map(id => parseInt(id, 10));
|
|
112
|
+
|
|
113
|
+
await db.client.collection(`search${key}`).deleteMany({ _id: { $in: ids } });
|
|
114
|
+
};
|
package/lib/postgres.js
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const winston = require.main.require('winston');
|
|
4
|
-
const nconf = require.main.require('nconf');
|
|
5
|
-
|
|
6
|
-
const db = require.main.require('./src/database');
|
|
7
|
-
const pubsub = require.main.require('./src/pubsub');
|
|
8
|
-
|
|
9
|
-
let searchLanguage = 'english';
|
|
10
|
-
|
|
11
|
-
pubsub.on('dbsearch-language-changed',
|
|
12
|
-
searchLanguage = e.data;
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
async function initDB() {
|
|
16
|
-
await db.pool.query('CREATE TABLE IF NOT EXISTS "searchtopic" ( "id" BIGINT NOT NULL PRIMARY KEY, "content" TEXT, "uid" BIGINT, "cid" BIGINT )');
|
|
17
|
-
await db.pool.query(
|
|
18
|
-
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchtopic__uid" ON "searchtopic"("uid")');
|
|
19
|
-
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchtopic__cid" ON "searchtopic"("cid")');
|
|
20
|
-
await db.pool.query('CREATE TABLE IF NOT EXISTS "searchpost" ( "id" BIGINT NOT NULL PRIMARY KEY, "content" TEXT, "uid" BIGINT, "cid" BIGINT )');
|
|
21
|
-
await db.pool.query(
|
|
22
|
-
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchpost__uid" ON "searchpost"("uid")');
|
|
23
|
-
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchpost__cid" ON "searchpost"("cid")');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function handleError(err) {
|
|
27
|
-
if (err && err.code === '42P01') {
|
|
28
|
-
winston.warn('dbsearch was not initialized');
|
|
29
|
-
await initDB();
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
throw err;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
exports.createIndices = async function (language) {
|
|
37
|
-
searchLanguage = language;
|
|
38
|
-
if (nconf.get('isPrimary') && !nconf.get('jobsDisabled')) {
|
|
39
|
-
await initDB();
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
exports.changeIndexLanguage = async function (language) {
|
|
44
|
-
searchLanguage = language;
|
|
45
|
-
pubsub.publish('dbsearch-language-changed', language);
|
|
46
|
-
await db.pool.query('DROP INDEX "idx__searchtopic__content"');
|
|
47
|
-
await db.pool.query(
|
|
48
|
-
await db.pool.query('DROP INDEX "idx__searchpost__content"');
|
|
49
|
-
await db.pool.query(
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
exports.searchIndex = async function (key, data, ids) {
|
|
53
|
-
if (!ids.length) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
ids = ids.map(id => parseInt(id, 10));
|
|
58
|
-
try {
|
|
59
|
-
await db.pool.query({
|
|
60
|
-
name:
|
|
61
|
-
text:
|
|
62
|
-
values: [ids, data],
|
|
63
|
-
});
|
|
64
|
-
} catch (err) {
|
|
65
|
-
winston.error(
|
|
66
|
-
await handleError(err);
|
|
67
|
-
await exports.searchIndex(key, data, ids);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
exports.search = async function (key, data, limit) {
|
|
72
|
-
if (Array.isArray(data.uid) && data.uid.filter(Boolean).length) {
|
|
73
|
-
data.uid = data.uid.filter(Boolean);
|
|
74
|
-
} else {
|
|
75
|
-
data.uid = null;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (Array.isArray(data.cid) && data.cid.filter(Boolean).length) {
|
|
79
|
-
data.cid = data.cid.filter(Boolean);
|
|
80
|
-
} else {
|
|
81
|
-
data.cid = null;
|
|
82
|
-
}
|
|
83
|
-
try {
|
|
84
|
-
const res = await db.pool.query({
|
|
85
|
-
name:
|
|
86
|
-
text:
|
|
87
|
-
values: [data.content, data.uid, data.cid, parseInt(limit, 10), searchLanguage],
|
|
88
|
-
});
|
|
89
|
-
return res.rows[0].r;
|
|
90
|
-
} catch (err) {
|
|
91
|
-
await handleError(err);
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
exports.searchRemove = async function (key, ids) {
|
|
97
|
-
if (!key || !ids.length) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
ids = ids.map(id => parseInt(id, 10));
|
|
102
|
-
try {
|
|
103
|
-
await db.pool.query({
|
|
104
|
-
name:
|
|
105
|
-
text:
|
|
106
|
-
values: [ids],
|
|
107
|
-
});
|
|
108
|
-
} catch (err) {
|
|
109
|
-
await handleError(err);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const winston = require.main.require('winston');
|
|
4
|
+
const nconf = require.main.require('nconf');
|
|
5
|
+
|
|
6
|
+
const db = require.main.require('./src/database');
|
|
7
|
+
const pubsub = require.main.require('./src/pubsub');
|
|
8
|
+
|
|
9
|
+
let searchLanguage = 'english';
|
|
10
|
+
|
|
11
|
+
pubsub.on('dbsearch-language-changed', (e) => {
|
|
12
|
+
searchLanguage = e.data;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
async function initDB() {
|
|
16
|
+
await db.pool.query('CREATE TABLE IF NOT EXISTS "searchtopic" ( "id" BIGINT NOT NULL PRIMARY KEY, "content" TEXT, "uid" BIGINT, "cid" BIGINT )');
|
|
17
|
+
await db.pool.query(`CREATE INDEX IF NOT EXISTS "idx__searchtopic__content" ON "searchtopic" USING GIN (to_tsvector('${searchLanguage}', "content"))`);
|
|
18
|
+
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchtopic__uid" ON "searchtopic"("uid")');
|
|
19
|
+
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchtopic__cid" ON "searchtopic"("cid")');
|
|
20
|
+
await db.pool.query('CREATE TABLE IF NOT EXISTS "searchpost" ( "id" BIGINT NOT NULL PRIMARY KEY, "content" TEXT, "uid" BIGINT, "cid" BIGINT )');
|
|
21
|
+
await db.pool.query(`CREATE INDEX IF NOT EXISTS "idx__searchpost__content" ON "searchpost" USING GIN (to_tsvector('${searchLanguage}', "content"))`);
|
|
22
|
+
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchpost__uid" ON "searchpost"("uid")');
|
|
23
|
+
await db.pool.query('CREATE INDEX IF NOT EXISTS "idx__searchpost__cid" ON "searchpost"("cid")');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function handleError(err) {
|
|
27
|
+
if (err && err.code === '42P01') {
|
|
28
|
+
winston.warn('dbsearch was not initialized');
|
|
29
|
+
await initDB();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
exports.createIndices = async function (language) {
|
|
37
|
+
searchLanguage = language;
|
|
38
|
+
if (nconf.get('isPrimary') && !nconf.get('jobsDisabled')) {
|
|
39
|
+
await initDB();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
exports.changeIndexLanguage = async function (language) {
|
|
44
|
+
searchLanguage = language;
|
|
45
|
+
pubsub.publish('dbsearch-language-changed', language);
|
|
46
|
+
await db.pool.query('DROP INDEX "idx__searchtopic__content"');
|
|
47
|
+
await db.pool.query(`CREATE INDEX "idx__searchtopic__content" ON "searchtopic" USING GIN (to_tsvector('${language}', "content"))`);
|
|
48
|
+
await db.pool.query('DROP INDEX "idx__searchpost__content"');
|
|
49
|
+
await db.pool.query(`CREATE INDEX "idx__searchpost__content" ON "searchpost" USING GIN (to_tsvector('${language}', "content"))`);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
exports.searchIndex = async function (key, data, ids) {
|
|
53
|
+
if (!ids.length) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ids = ids.map(id => parseInt(id, 10));
|
|
58
|
+
try {
|
|
59
|
+
await db.pool.query({
|
|
60
|
+
name: `dbsearch-searchIndex-${key}`,
|
|
61
|
+
text: `INSERT INTO "search${key}" SELECT d."id", d."data"->>'content' "content", (d."data"->>'uid')::bigint "uid", (d."data"->>'cid')::bigint "cid" FROM UNNEST($1::bigint[], $2::jsonb[]) d("id", "data") ON CONFLICT ("id") DO UPDATE SET "content" = COALESCE(EXCLUDED."content", "search${key}"."content"), "uid" = COALESCE(EXCLUDED."uid", "search${key}"."uid"), "cid" = COALESCE(EXCLUDED."cid", "search${key}"."cid")`,
|
|
62
|
+
values: [ids, data],
|
|
63
|
+
});
|
|
64
|
+
} catch (err) {
|
|
65
|
+
winston.error(`Error indexing ${err.stack}`);
|
|
66
|
+
await handleError(err);
|
|
67
|
+
await exports.searchIndex(key, data, ids);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
exports.search = async function (key, data, limit) {
|
|
72
|
+
if (Array.isArray(data.uid) && data.uid.filter(Boolean).length) {
|
|
73
|
+
data.uid = data.uid.filter(Boolean);
|
|
74
|
+
} else {
|
|
75
|
+
data.uid = null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(data.cid) && data.cid.filter(Boolean).length) {
|
|
79
|
+
data.cid = data.cid.filter(Boolean);
|
|
80
|
+
} else {
|
|
81
|
+
data.cid = null;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const res = await db.pool.query({
|
|
85
|
+
name: `dbsearch-search-${key}`,
|
|
86
|
+
text: `SELECT ARRAY(SELECT s."id" FROM "search${key}" s WHERE ($1::text IS NULL OR to_tsvector($5::regconfig, "content") @@ plainto_tsquery($5::regconfig, $1::text)) AND ($2::bigint[] IS NULL OR "uid" = ANY($2::bigint[])) AND ($3::bigint[] IS NULL OR "cid" = ANY($3::bigint[])) ORDER BY ts_rank_cd(to_tsvector($5::regconfig, "content"), plainto_tsquery($5::regconfig, $1::text)) DESC, s."id" ASC LIMIT $4::integer) r`,
|
|
87
|
+
values: [data.content, data.uid, data.cid, parseInt(limit, 10), searchLanguage],
|
|
88
|
+
});
|
|
89
|
+
return res.rows[0].r;
|
|
90
|
+
} catch (err) {
|
|
91
|
+
await handleError(err);
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
exports.searchRemove = async function (key, ids) {
|
|
97
|
+
if (!key || !ids.length) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
ids = ids.map(id => parseInt(id, 10));
|
|
102
|
+
try {
|
|
103
|
+
await db.pool.query({
|
|
104
|
+
name: `dbsearch-searchRemove-${key}`,
|
|
105
|
+
text: `DELETE FROM "search${key}" s WHERE s."id" = ANY($1::bigint[])`,
|
|
106
|
+
values: [ids],
|
|
107
|
+
});
|
|
108
|
+
} catch (err) {
|
|
109
|
+
await handleError(err);
|
|
110
|
+
}
|
|
111
|
+
};
|
package/lib/redis.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const async = require.main.require('async');
|
|
6
|
-
|
|
7
|
-
const db = require.main.require('./src/database');
|
|
8
|
-
|
|
9
|
-
exports.createIndices = async function () {
|
|
10
|
-
db.postSearch = redisSearch.createSearch('nodebbpostsearch', db.client);
|
|
11
|
-
db.topicSearch = redisSearch.createSearch('nodebbtopicsearch', db.client);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
exports.changeIndexLanguage = async function () {
|
|
15
|
-
// not supported
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
exports.searchIndex = async function (key, data, ids) {
|
|
19
|
-
const method = key === 'post' ? db.postSearch : db.topicSearch;
|
|
20
|
-
|
|
21
|
-
const indexData = ids.map((id, index) => ({ id: id, data: data[index] }));
|
|
22
|
-
|
|
23
|
-
await async.eachLimit(indexData, 500, async
|
|
24
|
-
await method.index(indexData.data, indexData.id);
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
exports.search = async function (key, data, limit) {
|
|
29
|
-
const queryMethod = key === 'post' ? db.postSearch : db.topicSearch;
|
|
30
|
-
|
|
31
|
-
const query = {
|
|
32
|
-
matchWords: data.matchWords,
|
|
33
|
-
query: {
|
|
34
|
-
cid: data.cid,
|
|
35
|
-
uid: data.uid,
|
|
36
|
-
content: data.content,
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return await queryMethod.query(query, 0, limit - 1);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
exports.searchRemove = async function (key, ids) {
|
|
44
|
-
if (!key || !ids.length) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
await async.eachLimit(ids, 500, async
|
|
50
|
-
await method.remove(ids);
|
|
51
|
-
});
|
|
52
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const redisSearch = require('redisearch');
|
|
4
|
+
|
|
5
|
+
const async = require.main.require('async');
|
|
6
|
+
|
|
7
|
+
const db = require.main.require('./src/database');
|
|
8
|
+
|
|
9
|
+
exports.createIndices = async function () {
|
|
10
|
+
db.postSearch = redisSearch.createSearch('nodebbpostsearch', db.client);
|
|
11
|
+
db.topicSearch = redisSearch.createSearch('nodebbtopicsearch', db.client);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.changeIndexLanguage = async function () {
|
|
15
|
+
// not supported
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
exports.searchIndex = async function (key, data, ids) {
|
|
19
|
+
const method = key === 'post' ? db.postSearch : db.topicSearch;
|
|
20
|
+
|
|
21
|
+
const indexData = ids.map((id, index) => ({ id: id, data: data[index] }));
|
|
22
|
+
|
|
23
|
+
await async.eachLimit(indexData, 500, async (indexData) => {
|
|
24
|
+
await method.index(indexData.data, indexData.id);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.search = async function (key, data, limit) {
|
|
29
|
+
const queryMethod = key === 'post' ? db.postSearch : db.topicSearch;
|
|
30
|
+
|
|
31
|
+
const query = {
|
|
32
|
+
matchWords: data.matchWords,
|
|
33
|
+
query: {
|
|
34
|
+
cid: data.cid,
|
|
35
|
+
uid: data.uid,
|
|
36
|
+
content: data.content,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return await queryMethod.query(query, 0, limit - 1);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
exports.searchRemove = async function (key, ids) {
|
|
44
|
+
if (!key || !ids.length) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const method = key === 'post' ? db.postSearch : db.topicSearch;
|
|
48
|
+
|
|
49
|
+
await async.eachLimit(ids, 500, async (ids) => {
|
|
50
|
+
await method.remove(ids);
|
|
51
|
+
});
|
|
52
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-dbsearch",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"description": "A Plugin that lets users search posts and topics",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"redisearch": "^1.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"eslint": "
|
|
26
|
-
"eslint-config-
|
|
27
|
-
"eslint-plugin-import": "2.
|
|
25
|
+
"eslint": "7.32.0",
|
|
26
|
+
"eslint-config-nodebb": "0.0.3",
|
|
27
|
+
"eslint-plugin-import": "2.25.2"
|
|
28
28
|
},
|
|
29
29
|
"nbbpm": {
|
|
30
|
-
"compatibility": "^1.
|
|
30
|
+
"compatibility": "^1.18.6"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/plugin.json
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
"description": "A Plugin that lets users search posts and topics",
|
|
5
5
|
"url": "https://github.com/barisusakli/nodebb-plugin-dbsearch",
|
|
6
6
|
"library": "./index.js",
|
|
7
|
-
"staticDirs": {
|
|
8
|
-
"dbsearch": "public"
|
|
9
|
-
},
|
|
10
7
|
"upgrades": [
|
|
11
8
|
"upgrades/dbsearch_change_mongodb_schema.js"
|
|
12
9
|
],
|
|
@@ -34,7 +31,7 @@
|
|
|
34
31
|
{ "hook": "filter:topic.search", "method": "filterSearchTopic" }
|
|
35
32
|
],
|
|
36
33
|
"acpScripts": [
|
|
37
|
-
"
|
|
34
|
+
"public/admin.js"
|
|
38
35
|
],
|
|
39
|
-
"templates": "./
|
|
36
|
+
"templates": "./templates"
|
|
40
37
|
}
|
package/public/.eslintrc
ADDED