code: function generateQuery (fields, options, not) {
    let $and = []
    const $or = []
    const result = {}
  
    for (const key in options)
      switch (key) {
      case 'and':
      case 'or':
        const query = {}
        query[`$${key}`] = mapValues(options[key], value => {
          return generateQuery(fields, value)
        })
        return query
      case 'not':
        return generateQuery(fields, options[key], true)
      case 'range':
        $and.push(generateRangeQuery(fields, options.range))
        break
      case 'match':
        if ('or' in options.match)
          for (const key in options.match.or) {
            const q = {}
            q[key] = options.match.or[key]
            $or.push(q)
          }
        else $and.push(mapValues(options.match, value =>
          Array.isArray(value) ? { $in: value } : value))
        break
      case 'exists':
        $and.push(mapValues(options.exists, (value, key) => {
          if (!(key in fields)) return void 0
  
          if (fields[key].isArray)
            return value ? { $ne: [] } : []
  
          return value ? { $ne: null } : null
        }))
        break
      default:
      }
  
    if (not)
      $and = $and.map(applyNotOperator)
  
    if ($and.length) result.$and = $and
    if ($or.length) result.$or = $or
  
    return result
  }
docs: Generate a mongoDB query from a fortune query object