-
Notifications
You must be signed in to change notification settings - Fork 28
Add search #352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add search #352
Conversation
…arch # Conflicts: # dadi/lib/controller/index.js # dadi/lib/model/index.js # dadi/lib/search/index.js # package.json # test/acceptance/db-connection.js # test/acceptance/search_collections.js # workspace/collections/vjoin/testdb/collection.books.json
…arch # Conflicts: # README.md # dadi/lib/index.js # dadi/lib/model/delete.js # dadi/lib/model/index.js # dadi/lib/model/update.js # dadi/lib/search/index.js # package.json # test/acceptance/search_collections.js # test/test-connector/index.js
config.js
Outdated
default: 3 | ||
}, | ||
wordCollection: { | ||
doc: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔
config.js
Outdated
default: 'words' | ||
}, | ||
datastore: { | ||
doc: "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😑
config.js
Outdated
default: '@dadi/api-mongodb' | ||
}, | ||
database: { | ||
doc: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😱
dadi/lib/controller/index.js
Outdated
let queryOptions = this._prepareQueryOptions(options) | ||
|
||
if (queryOptions.errors.length !== 0) { | ||
sendBackJSON(400, res, next)(null, queryOptions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, don't we want to return
?
dadi/lib/controller/index.js
Outdated
}) | ||
|
||
return help.sendBackJSON(200, res, next)(null, results) | ||
}).catch(error => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you don't need this catch
, since you have one on the parent Promise.
dadi/lib/search/index.js
Outdated
* @param {Object} options - options to use in the query | ||
* @return {Promise} | ||
*/ | ||
// Search.prototype.insert = function (datastore, data, collection, schema, options = {}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this meant to be commented out?
dadi/lib/search/index.js
Outdated
if (!Object.keys(this.indexableFields).length) return | ||
|
||
let skip = (page - 1) * limit | ||
console.log(`Indexing page ${page} (${limit} per page)`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a debug()
?
dadi/lib/search/index.js
Outdated
settings: this.model.settings | ||
}).then(results => { | ||
if (results.results && results.results.length) { | ||
console.log(`Indexed ${results.results.length} ${results.results.length === 1 ? 'record' : 'records'} for ${this.model.name}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a debug()
?
dadi/lib/search/index.js
Outdated
|
||
if (results.results.length > 0) { | ||
this.index(results.results).then(response => { | ||
console.log(`Indexed page ${options.page}/${results.metadata.totalPages}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a debug()
?
@@ -1,4 +1,3 @@ | |||
--bail |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not commit this change? I think it's useful if tests fail early in the CI.
…arch # Conflicts: # CHANGELOG.md
Pull Request Test Coverage Report for Build 1472
💛 - Coveralls |
…arch # Conflicts: # CHANGELOG.md # config/mongodb.test.json # package.json
dadi/lib/model/search.js
Outdated
let err | ||
|
||
if (typeof options === 'function') { | ||
// done = options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can go, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's gone!
|
||
areValidWords (words) { | ||
return Array.isArray(words) && | ||
words.every(word => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation here looks a bit off?
dadi/lib/search/index.js
Outdated
* N.B. May only be used with the MongoDB Data Connector. | ||
*/ | ||
const Search = function (model) { | ||
if (!model || model.constructor.name !== 'Model') throw new Error('model should be an instance of Model') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line? 😬
dadi/lib/search/index.js
Outdated
} | ||
} | ||
}).catch(err => { | ||
console.log(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if we go into this catch
? We're swallowing the error, so doesn't the request hang?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Promise.reject(err)
<- ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless we want to handle this error in a special way, I would just remove the catch
and let the error be handled upstream. But it needs confirmation (and ideally a unit test), I'm just being that annoying guy that points potential issues just by looking at the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted.
dadi/lib/search/index.js
Outdated
} | ||
|
||
if (!Array.isArray(documents)) { | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore if this doesn't make sense, but is it okay to be returning undefined
here where the other exit routes return a Promise? i.e. isn't there a risk that we'll add a .then()
somewhere upstream, which will throw an error if the subject is undefined
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't actually see us calling this method from anywhere.
@mingard any pointers to where I might find this being called?
dadi/lib/search/index.js
Outdated
|
||
debug('deleting documents from the %s index', this.searchCollection) | ||
|
||
let deleteQueue = documents.map(document => this.clearDocumentInstances(document._id.toString())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line? 😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably you mean:
let deleteQueue = documents.map(document => {
this.clearDocumentInstances(document._id.toString())
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let deleteQueue = documents.map(document => {
return this.clearDocumentInstances(document._id.toString())
})
(You were missing the return
)
dadi/lib/search/index.js
Outdated
Search.prototype.getIndexableFields = function () { | ||
let schema = this.model.schema | ||
|
||
return Object.assign({}, ...Object.keys(schema) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this return
statement super confusing 😞
dadi/lib/search/index.js
Outdated
Search.prototype.removeNonIndexableFields = function (document) { | ||
if (typeof document !== 'object') return {} | ||
|
||
return Object.assign({}, ...Object.keys(document) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this return
statement super confusing 😞
dadi/lib/search/index.js
Outdated
settings: this.getWordSchema().settings | ||
}).then(results => { | ||
// Get all word instances from Analyser | ||
this.clearDocumentInstances(docId).then(response => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we return this.clearDocumentInstances(docId)
?
dadi/lib/search/index.js
Outdated
options: options, | ||
schema: this.model.schema, | ||
settings: this.model.settings | ||
}).then(results => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor thing: perhaps we could use object destructuring here to avoid writing results.results
, so:
// (...)
}).then(({metadata, results}) => {
if (results && results.length) {
// (...)
dadi/lib/controller/searchIndex.js
Outdated
} | ||
|
||
// 404 if Search is not enabled | ||
if (config.get('search.enabled') === false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be more strict and do if (config.get('search.enabled') !== true) {
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
dadi/lib/search/index.js
Outdated
return Promise.resolve() | ||
} | ||
|
||
if (!Array.isArray(documents)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we merge this with the first if
, perhaps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Description
This PR introduces a search endpoint and indexing routine.
Configuration
A search block must exist in the configuration file:
minQueryLength
The number of characters required before a search can be executed
datastore
The data connector to use to store search collections. Currently supports @dadi/api-mongodb only.
database
The database to store words and search instances
Indexable fields
To enable indexing you must specify a
search
block for each field you'd like indexed within the collection schema, including the weight:Running a query
Query an indexed collection by adding
/search
to the collection's endpoint and include aq
parameter in the querystring:https://somedomain.com/1.0/my-db/books/search?q=harry wizard
Field filters can be applied in the same way as collection filtering"
https://somedomain.com/1.0/my-db/books/search?q=harry wizard&fields={"title": 1}