feathersjs-ecosystem / feathers-mongoose

Easily create a Mongoose Service for Feathersjs.
MIT License
189 stars 96 forks source link

Document using $regex #49

Closed marshallswain closed 8 years ago

marshallswain commented 8 years ago

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:

query = { fieldName: { $regex: 'pattern', $options: 'igm' } }

jamesjnadeau commented 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 :)

marshallswain commented 8 years ago

@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. :)

ekryski commented 8 years ago

@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.

daffl commented 8 years ago

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.

ekryski commented 8 years ago

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.

marshallswain commented 8 years ago

Closing in favor of that one.

radiegtya commented 5 years ago

$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?

marshallswain commented 5 years ago

Not a bug. Using $options requires specifying `whitelist: ['$regex', '$options'] in the mongoose service configuration.

radiegtya commented 5 years ago

Thanks @marshallswain its working!

Sciederrick commented 1 month ago
// 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 ?

jamesjnadeau commented 1 month ago

@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:

https://feathersjs.com/api/databases/querying#search

Sciederrick commented 1 month ago

@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.