I have a Foxx route like the following
const aql = require('@arangodb').aql;
route.get('ABC'){function(req,res){
//Do some stuffs
var AnArray1=req.queryParams.AnArray1||[DefaulArray]
var AnArray2=req.queryParams.AnArray2||[DefaulArray]
//Turn them into segment to put into AQL
var segment=aql.literal(AnArray1.length>0 ? 'AND u.Code IN '+ JSON.stringify(AnArray1) : '');
}
.queryParam('AnArray1', joi.any())
.queryParam('AnArray2', joi.any())
.response(['json/application'], 'Done task')
This throw back an aql.literal is not a function
. This is very strange to me since I thought it is a built-in.The version of arango is 3.3.5
Where did I went wrong?
v3.3.5 is 8 months old (released 2018-03-28), aql.literal
was added in v3.3.9 (2018-05-17):
An update to the latest 3.3 version (currently v3.3.17 from 2018-10-04) should fix the problem.
How you use aql.literal()
doesn't look very safe in regards to AnArray1
. There is no schema validation that would ensure that it's an array (joi.any()
) and you don't test for the type at any later point. Strings would actually pass req.queryParams.AnArray1||[DefaulArray]
and AnArray1.length>0
, and you would end up with a query segment like AND u.Code IN "some string"
, which will always be false.
The combination of aql.literal()
and JSON.stringify
is not recommended anymore. Starting with ArangoJS version 6.7.0 and ArangoDB v3.4.0-RC.2 in Foxx, nesting of AQL template strings is supported:
var coll = db.collection('test')
var AnArray1 = [ "foo", 2, -0.1, true, null, [ false, { bar: true } ] ]
var segment = (
Array.isArray(AnArray1) && AnArray1.length > 0
? aql`AND u.Code IN ${AnArray1}`
: undefined
)
var fullQuery = aql`FOR u IN ${coll} FILTER u.attr == true ${segment} RETURN u`
This results in fullQuery
being:
{
query: 'FOR u IN @@value0 FILTER u.attr == true AND u.Code IN @value1 RETURN u',
bindVars: {
'@value0': 'test',
value1: [ 'foo', 2, -0.1, true, null, [false, { bar: true } ] ]
}
}
With var AnArray1 = "foo"
you get this instead:
{
query: 'FOR u IN @@value0 FILTER u.attr == true RETURN u',
bindVars: { '@value0': 'test' }
}
As long as you want to AND
combine FILTER
criteria my suggestion would be to use
aql`FILTER u.Code IN ${AnArray1}`
because you can then use this segment as filter on its own, whereas AND ...
might not be valid in the full query (FILTER AND ...
).