0

I have few tables in rethinkdb with very varied datasets. Mostly because over time, out of simple string properties complex objects were created to be more expressive.

When I run a query, I'm making sure that all fields exist, with the hasFields - function. But what if I want to run a RegExp query on my Message property, which can be of type string or object. Of course if it is an object, I don't care about the row, but instead of ignoring it, rethinkdb throws the error:

Unhandled rejection RqlRuntimeError: Expected type STRING but found OBJECT in...

Can I somehow use typeOf to first determine the type, before running the query?

Or what would be a good way to do this?

peter
  • 14,348
  • 9
  • 62
  • 96

2 Answers2

2

Your question is not 100% clear to me so I'm going to restate the problem to make sure my solution gets sense.

Problem

Get all documents where the message property is of type object or the message property is a string and matches a particular regular expression (using the match method).

Solution

You basically need an if statement. For that, you can use the r.branch to 'branch' your conditions depending on these things.

Here's a very long, but clear example on how to do this:

Let's say you have these documents and you want all documents where the message property is an object or a string that has the substring 'string'. The documents look like this:

{
  "id":  "a1a17705-e7b0-4c84-b9d5-8a51f4599eeb" ,
  "message":  "invalid"
}, {
  "id":  "efa3e26f-2083-4066-93ac-227697476f75" ,
  "message":  "this is a string"
}, {
 "id":  "80f55c96-1960-4c38-9810-a76aef60d678" ,
  "not_messages": "hello"
}, {
  "id":  "d59d4e9b-f1dd-4d23-a3ef-f984c2361226" ,
  "message": {
    "exists": true ,
    "text":  "this is a string"
  }
}

For that , you can use the following query:

r.table('messages')
  .hasFields('message') // only get document with the `message` property
  .filter(function (row) { 
    return r.branch( // Check if it's an object
      row('message').typeOf().eq('OBJECT'), // return true if it's an object
      true,
      r.branch( // Check if it's a string
        row('message').typeOf().eq('STRING'),
        r.branch( // Only return true if the `message` property ...
          row('message').match('string'), // has the substring `string`
          true,
          false // return `false` if it's a string but doesn't match our regex
        ),
        false // return `false` if it's neither a string or an object
      )
    )
  })

Again this query is long and could be written a lot more elegantly, but it explains the use of branch very clearly.

A shorter way of writing this query is this:

r.table('messages')
  .hasFields('message')
  .filter(function (row) {
    return 
      row('message').typeOf().eq('OBJECT')
        .or(
          row('message').typeOf().eq('STRING').and(row('message').match('string'))
        )
  })

This basically uses the and and or methods instead of branch.

Jorge Silva
  • 4,574
  • 1
  • 23
  • 42
  • not really the answer to my question, but it very much clarifies how to use the typeOf function, that's all I need, thx very much – peter May 10 '15 at 18:13
  • I didn't really understand your question then. Can you clarify what the question was? Just out of curiosity. – Jorge Silva May 10 '15 at 18:39
  • 1
    yes, I wanted to just run match if the item is a string and ignore the object, so I can just skip the first part of your condition, but it was also good to see more complex queries as an example, thx – peter May 10 '15 at 18:47
0

This query will return you all registers on table message that have the field message and the field is String. Cheers.

r.db('test').table('message').hasFields('message')
.filter(function (row) { 
    return row('message').typeOf().eq('STRING')
})
Thomas Modeneis
  • 687
  • 8
  • 11