Does PostREST have a null-safe not-equal operator, like IS DISTINCT FROM? - postgresql

I'm making some simple PostgREST queries on a table with network device properties. It seems that eq and not.eq both exclude null values. I've learned that that's a “feature” of PostgreSQL, and can be worked around with the IS DISTINCT FROM operator, which treats null as a comparable value.
I can't find an equivalent (null-safe not-equals) operator in PostgREST. Is there one?
Simplified example:
# https://example.com/api?select=*&name=like.spam-*
[{
"name":"spam-eggs",
"type":"router",
"sector":"cheese"
},{
"name":"spam-ham",
"type":"router",
"sector":null
}]
not.eq.cheese excludes cheese and null:
# https://example.com/api?select=*&name=like.spam-*&sector=not.eq.cheese
[]
My awkward workaround is using or to include nulls:
# https://example.com/api?select=*&name=like.spam-*&or=(sector.not.eq.cheese,sector.is.null)
[{
"name":"spam-ham",
"type":"router",
"sector":null
}]
Am I stuck with that workaround, or is there an operator like isdistinctfrom, neq-or-null, etc. that I've missed?

I've checked the code and there's no implementation of IS DISTINCT FROM right now. That is, no PostgREST operator translates to it. The only reference I found is in a comment in this file, but it's for a different issue.
So, yes, right now, your workaround would be the closest you can get to the behavior you want. Creating a FUNCTION with a custom query using IS DISTINCT FROM is another alternative, although it requires more heavy lifting.

Related

How can I compare addresses with the 'eq' operator in Mongo

I'm using Mongo with Kotlin and I'm looking to compare an address category.
In this case, I have three addresses:
MAIN, DELIVERY & BILLING
So, if an address is MAIN I want to compare it with AddressCategory.MAIN, if not then with another address category and so on.
I'm quite a beginner in Kotlin, I tried to use the logical and ternary operators to make this comparison, but I couldn't.
eq(Address::category, AddressCategory.MAIN.toString()) ,
eq(Address::category, AddressCategory.DELIVERY.toString()),
eq(Address::category, AddressCategory.BILLING.toString())
The comparison would be like this, if the MAIN address does not exist I will do the comparison by DELIVERY, if it does not exist, I do it by BILLING, always with this order of precedence.
You can try to use when to do that. Something like:
when(Address::category) {
is AddressCategory.MAIN -> AddressCategory.MAIN.toString()
is AddressCategory.DELIVERY -> AddressCategory.DELIVERY.toString()
is AddressCategory.BILLING -> AddressCategory.BILLING.toString()
}
You will need to fill in the gaps since I don't have a complete understanding of that you are trying to accomplish but this can give you an idea of how you can try to implement this

JPA 2 criteria provide runtime type for gt operator

I am building a highly generic query mechanism on top of the JPA Criteria. I get as input an XML describing the query, something like this:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<Criteria xmlns='criteria' maxResults='2'>
<Expression>
<CompareRestriction propertyType='Date' operator='GREATER_THAN_OR_EQUALS' propertyName='deliveryDate'>2010-07-02</CompareRestriction>
<CompareRestriction propertyType='Float' operator='GREATER_THAN_OR_EQUALS' propertyName='weight'>10f</CompareRestriction>
<Restriction operator='NOT_NULL' propertyName='maxDiameter'/>
<LogicalExpression operator='OR'>
<LeftHandSideCompare propertyType="Integer" operator="EQUALS" propertyName="weight">31</LeftHandSideCompare>
<RightHandSide operator='NOT_NULL' propertyName='lastChangedDate'/>
</LogicalExpression>
<LogicalExpression operator='OR'>
<LeftHandSideCompare propertyType="Integer" operator="EQUALS" propertyName="weight">31</LeftHandSideCompare>
<RightHandSide operator='NOT_NULL' propertyName='lastChangedDate'/>
</LogicalExpression>
</Expression>
<Order propertyName='deliveryDate' type='DESC'/>
</Criteria>
and I parse this thing and build the corresponding criteria. Currently I am facing a problem with it comes to comparison operators (<,>,<=,=>) as I deal with different numerical types: I have fields with Float, Integer or Long value. So when I am mapping I do something like this:
switch (leftHandSideCompareRestriction.getOperator().value()) {
...
case "LESS_THAN" : innerPredicates.add(criteriaBuilder.gt(rootQuery.<Number>get(propName), NumberUtils.createNumber((value))));
case "LESS_THAN_OR_EQUALS" : innerPredicates.add(criteriaBuilder.gt(rootQuery.<Number>get(propName), NumberUtils.createNumber(value)));
...
}
The NumberUtils is the apache commons NumberUtils utility class
that returns a numerical type based on the input provided (Float, Integer, Long or Double). Now I need a mechanism to provide the type also for the
rootQuery<T>.get(propName)
at runtime, otherwise the JPA is complaining that I provided a Float instead of a Integer or the other way around. I tried several things and now I kind of ran out of ideas. I would highly appreciate and thoughts, ideas, suggestions about how to accomplish this in a robust fashion.
I seems that initially I missed something - I am not sure how. There some kind of issue in a different part. So, doing the query like this: it will work for sure. I tried with the following types:
Integer
Float
And it worked as expected for the following operations: >,<, <=, =>. In conclusion using Number and the NumberUtils fixes this issue in quite an elegant manner, as the appropriate type is created by the NumberUtils and JPA takes the top of the hierarchy for Number.

How to Correctly Build a MongoDB Nested property Name using C# Driver

I must be missing something blindingly obvious. Somebody please shame me;
I'm building 2.2 Aggregation queries, which aren't natively supported by the C# Linq Driver, so I'm having to build up stringified names for nested properties using dotted notation. Say I have a structure like this;
db.so.insert({
a:1,
b:2,
n : {
z:4,
x:5,
y: {
v:"value",
}
}
});
So to reference the "value" I would need to use the name n.y.v or n[y][v]. Now, since I'm receiving the choice of field property names for the query from the web client (http://www.demo.org/exampleQuery?field1=n&field2=y&field3=v) I need to construct the property names thus;
var fieldNameForQuery = field1+"."+field2+"."+field3;
I'm obviously nervous about this, so of course I'm defending against NOSQL Injection by sanitising my input parameters, but I'd much rather be using the C# driver for this instead.
I guess I'd like something like;
MongoDB.Driver.BuildNestedFieldName(field1, field2, field3));
which is basically what I've had to write myself, but it feels like a kludge, and I'd rather not maintain the responsibility for building DB safe field names this way.
There currently isn't a function to do what you are wanting. However, if all the function does is stick "."'s in the middle, then we aren't solving an injection problem because the stuff we are inserting can't have been injected... The injection problem would be solved by ensuring that "field1", "field2", and "field3" are valid values for field names. Of course, there isn't much that is invalid according to http://bsonspec.org/#/specification. The only thing we'd be checking for is that there aren't 2 null terminators in the string. So... that doesn't leave us with much we can do.
Does this make sense?

syntax for passing a regex query on mongo's own http rest interface

I'd like to use the standard MongoDB ReST interface ( http://www.mongodb.org/display/DOCS/Http+Interface ) to search for and return records with a wildcard match on a certain field - 'link_url' in this case. For instance passing 'acko' to match www.stackoverflow.com etc.
It looks like if I wanted an exact match I would use
http://127.0.0.1:28017/databaseName/collectionName/?filter_link_url=value
But I'd like to pass a regex to allow the partial match
I've tried combining the URL above in various ways with syntax like their snippet:
"match" : { "$regex" : "foo", "$options" : "ig" }
But had no luck. Can anyone help? I only need to do finds and ideally don't want to have to run another interface.
I know this is not related to your question per se, but I tried this on mongolab and this worked for me:
https://api.mongolab.com/api/1/databases/myDBName/collections/categories/?apiKey=myAPIKey&q={"keyname":{"$regex":"^Kampanje$","$options":"i"}}
This finds all keynames called "Kampanje" case insensitively. Note that the URL cannot contain spaces.
It looks like the REST interface (likely for safety), automatically escapes the fields passed through, and that embedded queries are not possible. What that means is both methods for passing in the required URL format seem to be excluded. For example:
db.collection.find({"url" : /acko.*/i})
This would translate to, in theory:
http://127.0.0.1:28017/databaseName/collectionName/$cmd/?filter_url=/acko.*/i
Unfortunately, that actually gets passed as (note the quotes):
{ "url" : "/acko.*/i" }
There are similar issues with the other form where you pass in the $regex command as an embedded document. This, and other issues are why the built-in REST interface is not the recommended solution for running queries against mongoDB. Instead you should look at Sleepy Mongoose), or node.js
I know you didn't want to use another interface, but sometimes it really is the best thing to do.

How do you query for, or insert as, specific types in MongoDB?

I'm using the Perl bindings for MongoDB, and it seems that when I insert numbers, they are sometimes counted as strings. When I add 0 to the number, it gets converted.
Is there a way, with the MongoDB Perl bindings, to specify the data type on insertion?
Is there also a way to query for specific types?
An example type query might look like this, if there was a "$type" function:
db.c.find({ key: { '$type': 'NumberLong' } });
MongoDB does contain a $type operator for checking against bson datatype: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24type
Unfortunately in Perl you are subject to the languages semantics ... There is no Number datatype in Perl just Scalar.
If Perl has decided to store your value as a string that is how it will go to BSON and $type will likely not match it correctly.
However it does look like the Perl driver attempts to.test if Perl can treat a string its saving as a number in which case.it.is.stored such; you may want to test this along with the $test operator.
Use the looks_like_number parameter in your perl MongoDB driver
http://search.cpan.org/~friedo/MongoDB-0.702.2/lib/MongoDB/BSON.pm#looks_like_number
Worked like a charm for me