2

Is it possible to query nearby point that match with one or more tags? This is the data that I have:

r.db("test").table("Member"):

{ "POSTALCODE":  "526494" ,
"lat":  "1.3640" , "lon":  "103.9531" ,
"memberId":  "22b99a77-5f73-4331-a5da-dcdc46a4b4e7" ,
"membertags": ["tag1" ,"tag2" , "tag3" ] ,
"point": { "$reql_type$":  "GEOMETRY" , "coordinates": [103.9531 ,1.364],"type":  "Point"}
} {
"POSTALCODE":  "525842" ,
"lat":  "1.3516" , "lon":  "103.9384" ,
"memberId":  "79844285-7781-4bd4-819e-db54f90b8c8d" ,
"membertags": ["tag2" ,"tag3" ,"tag4" ,"tag5"] ,
"point": {"$reql_type$":  "GEOMETRY" ,"coordinates": [103.9384 ,1.3516] ,"type":  "Point" }
}

As highlighted in How do I run a filter on a getNearest() query in RethinkDB?, I could filter getNearest using eq

var point = r.point(103.9531,1.364);  
r.db('test')
.table('Member')
.getNearest(point, {index: 'point', unit :'km'})
.filter(function(user) {
   return user('doc')('POSTALCODE').eq('525842') //1 RESULT
   //return user('doc')('membertags').eq('tag2') //EMPTY RESULT
})

but I could not get the result for multi-indexes (e.g. membertags) as suggested in rethinkdb with filter and getNearest commands (Option #1) - using .filter({membertags : 'tag2'}).

The secondary index was created using r.db("test").table("Member").index_create("membertags", multi=True). I'm aware that filter does not support secondary index, but could not find alternative solution that uses getNearest.

Community
  • 1
  • 1
totoro
  • 195
  • 1
  • 9

1 Answers1

1

If you can sacrifice performance to use filter instead of index, we can do this:

var point = r.point(103.9531,1.364);  
r.db('test')
.table('Member')
.getNearest(point, {index: 'point', unit :'km'})
.filter(function(user) {
  return user('doc')('membertags').contains('tag2')
})

Instead of using eq we now use contains to filter the result in which membertags field contaisn the tag.

Downside is that filter doesn't use index so performance maybe not that great.

kureikain
  • 2,304
  • 2
  • 14
  • 9
  • Thanks! - I could now extended it to match with either tags using `return user('doc')('membertags').contains(function (tag) {return tag.eq('tag1').or(tag.eq('tag2'));})` (code: http://pastebin.com/vTjChN0z) But this won't work for `.and` condition (i.e. return each record that match > 1 tags). Do I miss something here? – totoro Nov 12 '15 at 02:03
  • 1
    `and` will always return false, because a single tags cannot be equal to two values at a time. Inside predicate function, each time, an element of array is pass into the predicate function. Therefore you cannot use it with `and`. A way to check for this is using `setIntersection` like this: `filter(function(user) { return user('doc')('membertags').setIntersection(['tag2', 'tag4']).count().eq(2) })` setIntersection return values appear in both array, then count the size of result array – kureikain Nov 12 '15 at 04:54