Closed marshallswain closed 8 years ago
OMG thank you! Didn't know about this! (RTFM I'm saying to myself) I had created my own hook that parsed out a $search string and turned it into a regular expression, this is so much cleaner :)
@jamesjnadeau I'm so glad it helped. You had been through the headache of figuring out a solution, already. I'll get it in the docs so we can save some devs the trouble. :)
@jamesjnadeau we had the idea of adding a common $search
attribute that does this mapping for you based on the DB adapter you are using. I thought we had an issue somewhere, if not I'll create them as it's a pretty common requirement.
This came up on Gitter before I think. I recommended using a before
hook that converts a special property into a regular expression. $search
or $like
per property (e.g. { name: { $like: 'Da' } }
would be nice though. I think most DBs support some kind of fuzzy search.
For now, a hook is a decent way to go about it but I think we should support a $search
or $like
param. I've created #50 in this repo to track progress.
Closing in favor of that one.
$regex
is working just fine, but $options
did not working. It said
"Unexpected error value: { name: \"BadRequest\", message: \"Invalid query parameter $options\", code: 400, className: \"bad-request\", data: { $regex: \"P\", $options: \"i\" }, errors: {} }"
Is this not a bug?
Not a bug. Using $options
requires specifying `whitelist: ['$regex', '$options'] in the mongoose service configuration.
Thanks @marshallswain its working!
// Schema for allowed query properties
export const userQueryProperties = Type.Pick(userSchema, ['_id', 'email', 'githubId'])
export const userQuerySchema = Type.Intersect(
[
querySyntax(userQueryProperties, { email: { $regex: Type.String() } }),
// Add additional query properties here
Type.Object({}, { additionalProperties: false })
],
{ additionalProperties: false }
)
export type UserQuery = Static<typeof userQuerySchema>
export const userQueryValidator = getValidator(userQuerySchema, queryValidator)
My Hook:
// For more information about this file see https://dove.feathersjs.com/guides/cli/hook.html
import type { HookContext } from '../declarations'
export const execAsRegExSearch = async (context: HookContext) => {
console.log(`Running hook execAsRegExSearch on ${context.path}.${context.method}`)
const { query } = context.params
if (query.email) {
// query.email = { $regex: new RegExp(query.email, 'i') }
query.email = { $regex: query.email, $options: 'igm' }
}
return context
}
Frontend request:
const response = await client.service("users").find({
query: {
// email: { $regex: new RegExp(email, 'i')},
email,
$limit: 10,
},
});
Error:
error: BadRequest: Invalid query parameter $regex
at validateQueryProperty (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/adapter-commons/src/query.ts:17:13)
at /home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/adapter-commons/src/query.ts:63:21
at Array.reduce (<anonymous>)
at getQuery (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/adapter-commons/src/query.ts:57:15)
at filterQuery (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/adapter-commons/src/query.ts:156:12)
at UserService.sanitizeQuery (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/adapter-commons/src/service.ts:108:43)
at UserService.find (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/mongodb/src/index.ts:22:25)
at UserService.<anonymous> (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/hooks/script/hooks.js:37:49)
at UserService.dispatch (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/hooks/script/compose.js:30:43)
at UserService.dispatch (/home/derrick/WebProjects/feathers-chat/node_modules/@feathersjs/hooks/script/compose.js:30:43)
What am I doing wrong @marshallswain ?
@Sciederrick, Seems like things have changed since this thread was written 8 year ago... I would suggest you open up a new one instead of piling on this one.
That being said, I don't think $regex is around anymore because you'd need to customize search functionality to your specific use case so it's actually performent and useful:
@jamesjnadeau I solved it with some help from discord.
export const userQueryProperties = Type.Pick(userSchema, ['_id', 'email', 'githubId'])
export const userQuerySchema = Type.Intersect(
[
querySyntax(userQueryProperties, {
email: { $regex: Type.String(), $options: Type.String() } // add this for $regex support
}),
// Add additional query properties here
Type.Object({}, { additionalProperties: false })
],
{ additionalProperties: false }
)
// In your class module
export const getOptions = (app: Application): MongoDBAdapterOptions => {
return {
paginate: app.get('paginate'),
Model: app.get('mongodbClient').then((db) => db.collection('users')),
operators: ['$regex', '$options'] // add this line
}
}
@jamesjnadeau do you think this example would be useful to polish the example from the docs. I would like to contribute.
Although there are three possible regular expression syntaxes that MongoDB supports, only one will work with Feathers providers thanks to the body-parser. This took me a while to figure out. Basically you can't use an actual RegExp object and have to instead pass this syntax: