rethinkdb with filter and getNearest commands

2019-04-12 00:28发布

问题:

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"

回答1:

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.