3

How can execute getNearest query about the result of other command, for example a filter command?

var point = r.point(-122.422876,37.777128);  
r.db('test').table('users').
   filter({tags : 'tag'}).
   getNearest(point, {index: 'geodata', maxResults: 30, unit :'km'})

I have a 'users' table:

 [ 
   {id: 1, tags : ['music', 'cups'], geodata: r.point()} 
   {id: 2, tags: ['music', 'play'], geodata: r.point()} 
 ] 

First I want to filter by 'tags' field and then return the nearest.

The query that I have specified is incorrect, return the follow error: "RqlRuntimeError: Expected type TABLE but found SELECTION"

Nick K
  • 379
  • 1
  • 3
  • 18
dloprodu
  • 33
  • 5
  • I can't really understand what your asking. Can you be a bit more specific? The query you have right now seem correct, presupposing every document in the `users` table has a `geodata` field that is a geospatial secondary index. Does that help? What kind of problems are you running into? – Jorge Silva Apr 19 '15 at 17:16
  • I have a 'users' table: [ {id: 1, tags : ['music', 'cups'], geodata: r.point()} {id: 2, tags: ['music', 'play'], geodata: r.point()} ] First I want to filter by 'tags' field and then return the nearest. The query that I have specified is incorrect, return the follow error: "RqlRuntimeError: Expected type TABLE but found SELECTION" – dloprodu Apr 19 '15 at 17:42
  • Now I see the problem. Added a solution below! – Jorge Silva Apr 19 '15 at 21:49

1 Answers1

5

The reason why your query throws an error is because .getNearest only works with tables. That's what the documentation says.

Option #1

You can solve your problem by just inverting the order of of commands:

var point = r.point(-122.422876,37.777128);  
r.db('test')
 .table('users')
 .getNearest(point, {index: 'geodata', maxResults: 30, unit :'km'})
 .filter({tags : 'tag'})

This works because .getNearest returns an array and .filter can work on an array.

var point = r.point(-122.422876,37.777128);  
r.db('test')
 .table('users')
 .getNearest(point, {index: 'geodata', unit :'km'})
 .filter({tags : 'tag'})
 .limit(30)

The problem this approach is that, in order to guarantee that all possible results are there, you can't pass a maxResults option to getNearest, which means every single row will be queried and then filtered.

This scenario works best for when most items will pass through the filter.

Depending on your data, it's also possible to write a function that increases maxResults incrementally until it gets all the results it needs, but this might be complex and not very elegant.

Option 2

If the filter is going to filter out most of the results, then you can filter the results using getAll (creating a tags index) and have getAll filter the results first and then order the results based on distance:

var point = r.point(-122.422876,37.777128);
r.table('users')
 .getAll('tag', {index: 'tags'})
 .orderBy(r.row('geodata')
 .distance(point))
 .limit(30)

Data Types

You can always get the type of a anything at any point by using the .typeOf method.

Example:

r.db('test')
 .table('users').typeOf() // "TABLE"

r.db('test')
 .table('users')
 .filter({tags : 'tag'}).typeOf() // "STREAM"

If you want to know more about ReQL data types, you can check out this blog post I wrote which explains ReQL data types and how they are different.

Jorge Silva
  • 4,574
  • 1
  • 23
  • 42
  • Exists two problem with yout solution. **1.** For to ensure results if there, I have to remove "maxResults" restriction in getNearest. **2.** If I remove "maxResults" restriction the query can be very slow because the filter command not work with indexs. – dloprodu Apr 20 '15 at 09:10
  • I'm 100% aware of that. I added another possible way to about it using `getAll` and `orderBy`. – Jorge Silva Apr 21 '15 at 18:38
  • Just to be clear, you are running into a current limitation in the database. This is something we're working on at RethinkDB. A possible solution to this is geospatial compound indexes: https://github.com/rethinkdb/rethinkdb/issues/2855 – Jorge Silva Apr 21 '15 at 18:40