How to check the type of a field before checking the value in rethinkdb? - typeof

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?

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.

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')
})

Related

define expression in camunda

I have a process that has a custom model, similar to the following model(get by calling http://localhost:8080/engine-rest/task/{id}/variables/):
{
"Title": {
"type": "String",
"value": "aaa",
"valueInfo": {
}
},
"247f3af4-36cf-72cc-1a95-601f07640674": {
"type": "String",
"value": "{\"Title\":\"AA\",\"Value\":\"BB\"}",
"valueInfo": {
}
}
}
I want to define a expressions at the gates. How should I do this?
I try these:
${ "247f3af4-36cf-72cc-1a95-601f07640674".Value == "AA"}
Or
${ JSON("247f3af4-36cf-72cc-1a95-601f07640674").prop("Value") == "AA"}
Or
${S(247f3af4-36cf-72cc-1a95-601f07640674).prop("Value").stringValue() == "AA"}
But get following errors:
Unknown property used in expression: ${ "247f3af4-36cf-72cc-1a95-601f07640674".Value == "AA"}. Cause: Could not find property Value in class java.lang.String
Error while evaluating expression: ${ JSON("247f3af4-36cf-72cc-1a95-601f07640674").prop("Value") == "AA"}. Cause: Error invoking function 'JSON'
ENGINE-01009 Error while parsing process. Error parsing '${S(247f3af4-36cf-72cc-1a95-601f07640674).prop("Value").stringValue() == "AA"}': syntax error at position 15, encountered 'c7', expected ')'.
What you are showing is the value of a JSON object stored in a process data, right? What is the name of the process data?
In Java you use JSON(), in the process (JavaScript) use S()
(see https://docs.camunda.org/manual/7.17/reference/spin/json/01-reading-json/)
Place S() around the name of your process data to create the object. Then you can use .prop() to navigate it. ${S(myData).prop("xyz")}.
In this example I used the method to read the JSON response of a REST call and then extract a field:
https://github.com/rob2universe/camunda-http-connector-example
You use JSON() around the name of the process data, then you can access the properties
I finally find answer
I must use something like this:
${S(a247f3af4_36cf_72cc_1a95_601f07640674).prop("Value").stringValue() == "AA"}
we must start variable name with character and do'nt use -.

MongoDB: Aggregation using $cond with $regex

I am trying to group data in multiple stages.
At the moment my query looks like this:
db.captions.aggregate([
{$project: {
"videoId": "$videoId",
"plainText": "$plainText",
"Group1": {$cond: {if: {$eq: ["plainText", {"$regex": /leave\sa\scomment/i}]},
then: "Yes", else: "No"}}}}
])
I am not sure whether it is actually possible to use the $regex operator within a $cond in the aggregation stage. I would appreciate your help very much!
Thanks in advance
UPDATE: Starting with MongoDB v4.1.11, there finally appears to be a nice solution for your problem which is documented here.
Original answer:
As I wrote in the comments above, $regex does not work inside $cond as of now. There is an open JIRA ticket for that but it's, err, well, open...
In your specific case, I would tend to suggest you solve that topic on the client side unless you're dealing with crazy amounts of input data of which you will always only return small subsets. Judging by your query it would appear like you are always going to retrieve all document just bucketed into two result groups ("Yes" and "No").
If you don't want or cannot solve that topic on the client side, then here is something that uses $facet (MongoDB >= v3.4 required) - it's neither particularly fast nor overly pretty but it might help you to get started.
db.captions.aggregate([{
$facet: { // create two stages that will be processed using the full input data set from the "captions" collection
"CallToActionYes": [{ // the first stage will...
$match: { // only contain documents...
"plainText": /leave\sa\scomment/i // that are allowed by the $regex filter (which could be extended with multiple $or expressions or changed to $in/$nin which accept regular expressions, too)
}
}, {
$addFields: { // for all matching documents...
"CallToAction": "Yes" // we create a new field called "CallsToAction" which will be set to "Yes"
}
}],
"CallToActionNo": [{ // similar as above except we're doing the inverse filter using $not
$match: {
"plainText": { $not: /leave\sa\scomment/i }
}
}, {
$addFields: {
"CallToAction": "No" // and, of course, we set the field to "No"
}
}]
}
}, {
$project: { // we got two arrays of result documents out of the previous stage
"allDocuments" : { $setUnion: [ "$CallToActionYes", "$CallToActionNo" ] } // so let's merge them into a single one called "allDocuments"
}
}, {
$unwind: "$allDocuments" // flatten the "allDocuments" result array
}, {
$replaceRoot: { // restore the original document structure by moving everything inside "allDocuments" up to the top
newRoot: "$allDocuments"
}
}, {
$project: { // include only the two relevant fields in the output (and the _id)
"videoId": 1,
"CallToAction": 1
}
}])
As always with the aggregation framework, it may help to remove individual stages from the end of the pipeline and run the partial query in order to get an understanding of what each individual stage does.

Where / and filtering in a query returns empty values on matching results

After working with loopback for the past 6 months, i have now encountered a problem i can't seem to figure out the reason for.
My problem occurs when using loopbacks, "where" with a "and" condition.
Like.find({
"where: {
"and": [{
"relation_id": ctx.instance.relation_id
},
{
"user_id": ctx.options.accessToken.userId
}
]
}
})
Above is the call with the where/and filter included.
I console.log the values before the call and see:
"ctx.instance.relation_id" which prints "59a32764029ab660b1c7f862"
"ctx.options.accessToken.userId" which prints "59a32597c606a85b5e08db18"
And below is the object i am trying to query:
{
"_id" : ObjectId("59a5cade884d8c48e135768c"),
"user_id" : "59a32597c606a85b5e08db18",
"relation_id" : "59a32764029ab660b1c7f862",
"created_at" : ISODate("2017-08-29T22:13:18.209+02:00"),
"status" : NumberInt("1")
}
Now. Calling the find() function without the "and" condition for just one of the values, either user_id or relation_id, returns the expected result, but with the "and" it returns an empty array.
The official Loopback documentation gives this examples for using the where/and filter:
Post.find({where: {and: [{title: 'My Post'}, {content: 'Hello'}]}},
function (err, posts) {
...
});
as shown here
And as far as i can tell, my query matches it completely, but still don't get the expected results. I know that there could be many reasons why it fails, but i was hoping someone here, maybe could give some pointers or provide insight i could use to solve my issue.
Thanks

Mongodb distinct query with contains query

I have a mongo collection User which contains data like:-
{
id : 1,
name : "gaurav",
skills : "C++ HTML CSS"
}
when I am searching for all users that have C++ skill in it with the following query I am getting correct results as expected
db.user.find({skills:{contains:"C++"}});
But when I am searching all the unique names from the user using the same condition I m not getting any desired result
db.user.distinct('name',{skills:{contains:"C++"}});
Can anyone help me with what I am doing wrong?
The "contains" is not a valid keyword for MongoDB queries. You need $regex which submits a general "regular expression" statement matching the pcre specifications:
db.user.distinct( "name", { "skills": { "$regex": "C\+\+" } })
If using JavaScript as you language then this is also safe:
db.user.distinct( "name", { "skills": /C\+\+/ })
To determine if the string "C++" occurred somewhere within the string value of the field being tested. The + character is reserved in "regex" operations and therefore you need to escape it with a \ char as the standard escaping mechanism.
On your data this is the result:
db.user.distinct( "name", { "skills": { "$regex": "C\+\+" } })
[ "gaurav" ]
Try to use REGEX like below query
db.user.distinct("name",{"skills":{"$regex":"C++.*"}})

regular expressions: in a JSON array, get the id of the object that has status waiting

I have a JSON response that I want to parse with regular expressions that contains an array of objects like
...
{
"Id":"01",
"Subject":"Sub",
....
"Status":"Completed"
...
},
{
"Id":"02",
"Subject":"Sub",
....
"Status":"Waiting"
...
}
and I want to get the id of the object that has status waiting.
When I parse with "Id": "(.+?)",[\s\S]+?"Subject": "Sub",[\s\S]+?"Status": "Waiting"; it matches from "Waiting" to the first "Id" (backwards); certainly I want the Id of the object that is waiting.
Try this:
{\s*"Id":"(\d+)"[^}]+"Status":"Waiting"\s*}
Try this one:
(?s)"Id":\s*"([^"]+)[^}]*?"Status":\s*"Waiting"
It will work if there is no nested { } between properties Id and Status.
If you can use a Json Parser, please use that.
This will work as long as there are no nested brackets.
{[^{}]*Id":"(\d+)[^{}]*\s"Status":"Waiting"
See it here on Regexr
Your expression
"Id": "(.+?)",[\s\S]+?"Subject": "Sub",[\s\S]+?"Status": "Waiting"
^^^^^^^^
fails here
That part matches anything from the first "Sub", till it finds the first "Status": "Waiting"