graphql-compose-mongoose icon indicating copy to clipboard operation
graphql-compose-mongoose copied to clipboard

$or condition in the resolver filter root is not interpreted

Open ziedHamdi opened this issue 5 years ago • 2 comments

I'm trying to wrap the findMany resolver to modify its filter before calling it

const usersByNameOrMail = userMany.wrapResolve((next => async rp => {
	const {user} = rp.context
	const name = rp.args.filter.name
	const regExp = new RegExp(name, 'i');
	const filter = {$or: [{name: regExp}, {'facebook.emails.value':regExp}]}
        console.log("filter : ", filter)
	rp.args.filter = filter
	return await next(rp)
}))

schemaComposer.Query.addFields({
	usersByNameOrMail,
}

When activating mongoose logs I get these logs which show no filtering was made:

filter :  { '$or': [ { name: /zh/i }, { 'facebook.emails.value': /zh/i } ] }
Mongoose: users.find({}, { limit: 1000, projection: { _id: true, name: true, facebook: true, filter: true, skip: true, limit: true, sort: true } })

ziedHamdi avatar Jan 16 '20 13:01 ziedHamdi

Naturally, if I comment the line

rp.args.filter = filter

the filtering works correctly: Mongoose: users.find({ name: 'zh' }, { limit: 1000, projection: { _id: true, name: true, facebook: true, filter: true, skip: true, limit: true, sort: true } })

ziedHamdi avatar Jan 16 '20 13:01 ziedHamdi

You need to dig a little bit findMany resolver:

https://github.com/graphql-compose/graphql-compose-mongoose/blob/f819521650e8ed7c528acf1190500907ed04eec9/src/resolvers/findMany.js#L52-L61

  1. filter param will be processed by filterHelper and it will pass only existed fields from filter param for security reasons. So you cannot add mongoose query to it directly.

  2. but you may modify mongoose query in beforeQueryHelper something like that:

const usersByNameOrMail = userMany.wrapResolve((next => async rp => {
	const {user} = rp.context
	const name = rp.args.filter.name
	const regExp = new RegExp(name, 'i');
        rp.beforeQuery = (query) => {
          query['$or'] = [{name: regExp}, {'facebook.emails.value':regExp}];
          return query;
        }
	return await next(rp)
}))
  1. But more safer way will be to use special helper method Resolver.addFilterArg():
userMany.addFilterArg({
    name: 'name',
    type: 'String',
    description: 'Multiple field search with regExp',
    query: (query, value, resolveParams) => {
      const regExpValue = new RegExp(value, 'i');
      query['$or'] = [
        {name: regExp},
        {'facebook.emails.value':regExp},
      ];
    },
  })

More details and examples here https://github.com/graphql-compose/graphql-compose/issues/22

nodkz avatar Jan 21 '20 09:01 nodkz