I can't find out if it's possible to invoke AQL queries set up on the ArangoDb web UI in Foxx script - rather like stored procedures can be called by services of a RDMS.
So far all examples I've seen show the AQL embedded into the Foxx services JavaScript.
const result = db._query([name of query defined in Db], {
"#arg": arg-value
}).toArray();
I would expect the query defined on the ArangoDb to run and pass argument value from Foxx service. but the _query method seems to only accept a query string.
The queries are stored as properties of the user and as such are available via the users-API:
var _ = require("lodash"); // helper to group the queries
var users = require('#arangodb/users');
var myQueries = _.groupBy(users.document(users.currentUser())['extra']['queries'], 'name');
const result = db._query(myQueries['name of query defined in Db'], ...);
lodash is available per default, no need to install it.
This is not clearly documented anywhere -- I took a look at the network traffic of the query-editor, to find the queries under 'extra/queries' of the user; than I searched for a js user-API and found an article on 'User Managment'. I'd say the lack of documentation is a clear 'caveat emptor' -- it might change without notice; but this should get you going.
Additionally, thinking a bit, I only tested this in arangosh, not a foxx app -- maybe the users module isn't available there. If it works you will probably have to replace the users.currentUser() call with the username as string.
Given the ease this approach lends to breaking your application, I wouldn't recommend to use this (if it works...) outside of R&D and/or prototyping.
Edit: I implemented this to test it:
router.post(
'/getQueries',
/**
* #param {Object} req
* #param {Object} res
*/
function(req, res) {
var _ = require("lodash"); // helper to group the queries
var users = require('#arangodb/users');
var myQueries = _.groupBy(users.document(req.body.user, ['extra']['queries'], 'name'));
res.json({success: (myQueries !== null), queries: myQueries, error: null});
}).summary('Return queries stored for the given user').body(joi.object().keys({
'user': joi.string().required()
}).unknown(true), ['json']);
This works, the queries are objects with of the following form:
[
"value" => """
FOR x IN #params\n
RETURN x
""",
"parameter" => [
"params" => "",
],
"name" => "x_test",
],
so a foxx service can indeed access and execute queries stored for a user, but I still strongly suggest to not do this in production.
Related
This is a follow up to the successful call using Netsuite Token Based Authentication (TBA) REST webservice,
I would like to get some guidance on how to perform a query.
I am supposed to read records like this (please see screenshot)
how can I perform a specifc query (by table for a list of records and also specific record) ?
https://gist.github.com/axilaris/4386c3537d04737d3775c156562b7545 <-- here is the python code for the TBA that has worked successful. I would like to know how to construct the next step on how to perform the query and read specific record (as shown in the screenshot).
This is a custom record with an ID like this customrecord1589
To query a specific record: You're going to need to create/ deploy a RESTlet in Netsuite similar to the following:
/**
* #NApiVersion 2.1
* #NScriptType Restlet
*/
define([
"N/log",
"N/search",
], function (log, search) {
function post(context) {
return JSON.stringify(getCustomRecords(context));
}
function getCustomRecords(context) {
log.debug('POST Context', context);
return search.lookupFields({
//Change CUSTOM_RECORD to the type of custom record you are querying
type: search.Type.CUSTOM_RECORD + '1589',
id: context.id,
columns: context.fields,
});
}
return {
post: post,
};
});
In your Python Script: Make sure you change the URL of the request to the deployment URL of this new RESTlet. Also, make sure to pass any parameters you need (like 'id' or 'fields' in my example) in your POST request payload. So instead of:
payload = {
"name":"value",
"foo":"bar",
"duck":"hunt",
}
pass
payload = {
"id":"9999999",
"fields": ["custrecord_field1", "custrecord_field2"],
}
where id is the internalid of the record you want to query and the fields array are the internalids of the fields you want values from.
If this goes successfully, the result should show up as conn.text in your python script!
def get_campaigns_insight(self, start_date, end_date, batch_size):
params = {
'time_range': {'since':start_date,'until':end_date},
'filtering': [],
'level': 'campaign',
'breakdowns': ['country'],
'limit': batch_size,
'date_preset': 'lifetime',
}
fields = ['campaign_name', 'canvas_avg_view_percent']
response = self.account.get_insights(
fields=fields,
params=params,
)
data = str(response)
Currently I am passing the field names in a list and throwing it into the parameters as an argument, this works and i can manually add the names from the documentation, but surely there should be a way to get all the fields available right?
There is no way to get ALL fields, else a lot of users would use the oppertunity and use bandwith they do not really need - because you will most likely not need ALL fields. For all API calls, Facebook only returns a few default fields and additional fields you specify.
I am new to MongoDB and CRUD APIs.
I have created my first database and inserted some data. I can do get, post and delete requests.
Now I want to request a 'get' by adding a parameter, so I do the following:
router.get('/:story_name', async function (req, res, next) {
const selectedStory = await loadStoryToRead()
res.send(await selectedStory.find({}).toArray())
})
say that story_name is S1C1,
I can do http://localhost:3000/api/whatever/s1c1 to get the data.
I would have expected to retrieve the data ONLY by using the specified parameter, however I can use the ID or the date or any other parameter found in the json file to get the data.
for example I can do
http://localhost:3000/api/whatever/5d692b6b21d5fdac2... // the ID
or
http://localhost:3000/api/whatever/2019-08-30T13:58:03.035Z ... // the created_at date
and obtain the same result.
Why is that?
How can I make sure that if I use router.get('/:story_name' ... I can retrieve the data only if I use the 'story_name' parameter?
Thanks!
* UPDATE *
my loadStoryToRead() looks like this:
async function loadStoryToRead () {
const client = await mongodb.MongoClient.connect(
'mongodb+srv://...', {
useNewUrlParser: true
})
return client.db('read').collection('selectedStory')
}
I will try to reformulate my question.
I want to ensure that the data is retrieved only by adding the 'story_name' parameter in the URL and not by adding any other parameter within the file.
The reading that I have done suggested to add the parameter to the get request, but when I do it, it doesn't matter what parameter I enter, I can still retrieve the data.
The delete request, however, is very specific. If I use router.delete('/:id'... the only way to delete the file is by using the ID parameter.
I would like to obtain the same with a get request and not using the 'id' but by using 'story_name'.
you can use regular expression capabilities for pattern matching strings in queries.
Syntax is:
db.<collection>.find({<fieldName>: /<string>/})
for example, you can use
var re = new RegExp(req.params.story_name,"g");
db.users.find({$or:[{"name": re}, {"_id": re}, {..other fields}]});
You can use $and and $or according to your requirement.
To read more follow the link
https://docs.mongodb.com/manual/reference/operator/query/regex/
I am trying to insert a vertex with orientjs(previously oriento) query builder. My class has a link type property pointing to another class.
I know I can get it to work with a raw query string but I would love to use the query builder.
Here is what I've tried so far :
db.insert()
.into('VertexClassName')
.set({"prop":"value", "linkProperty":"33:1289287"})
db.insert()
.into('VertexClassName')
.set({"prop":"value", "linkProperty":"#33:1289287"})
I get the following error :
Error on saving record in cluster #13
Am I setting properties in the right way ?
Could the error be related to somtehing else ?
I have sucessfully ran an insert query in the cluster #13 with a raw query string in the studio...
According to the official documentation it seems that the problem might be at the end of your statement
db.insert().into('VertexClassName')
.set({"prop":"value", "linkProperty":"33:1289287"}).one()
.then(function (data) {
// callback
});
Check if your code works adding one() to the pipe line
EDITED: I found this method in orientjs.
db.create('VERTEX', 'V')
.set({
key: 'value',
foo: 'bar'
})
.one()
.then(function (vertex) {
console.log('created vertex', vertex);
});
When using Tinkerpop API they recommend using createVertex instead of insert, because createVertex is intended for graphs and insert for Documents... Could you try with the create() method instead?
I am using SQL and it worked.
sql = "INSERT INTO Station set linked = (select from LinkedClass where LinkedProb = 'value'), prop = 'value'"
OrientVertex vertex = new OrientVertex();
vertex = graph.command(new OCommandSQL(sql)).execute();
I don't think that's possible unless you've added a proper field with the right type 'Link' in your schema. (which I rarely do).
Now instead of having the right 'link' type inserted you can do the opposite, store is as a String, and leverage the query functions to use it correctly:
db.insert().into('table').set({prop: '#15:14'}).one();
And it will be converted as String (which is a bit sad) but then you can use that in your queries:
SELECT eval(prop) FROM table;
And it will be 'eval'-ed to a Node RecordID that you can directly use and call functions like expand() on.
For example:
SELECT name FROM (SELECT expand(eval(prop)) FROM table);
Will eval the node stored in the insert(), grab the node, expand it and collect its name property.
How can I avoid sql injection Azure DocumentDB stored procedures?
Apart from sanitizing the input (whitelisted characters) what's the best practice here?
Take for example the following stored procedure adapted from the MSDN example:
function simple_sp(s1) {
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();
collection.queryDocuments(collection.getSelfLink(),
'SELECT * FROM Families f where f.id = "' + s1 + '"', {},
function(res){}
);
}
That s1 parameter is a standard example injecting sql into the query. So far I have not found a way to parametrize the query either.
Update:
Happy to say that as of 1/14/15 - DocumentDB does support SQL parameterization. Support has been added across the .NET, Java, Node.js, and Python SDKs, as well as the REST API. Enjoy =)
Here's an example using the .NET SDK:
IQueryable<Book> queryable = client.CreateDocumentQuery<Book>(collectionSelfLink, new SqlQuerySpec {
QueryText = "SELECT * FROM books b WHERE (b.Author.Name = #name)",
Parameters = new SqlParameterCollection() {
new SqlParameter("#name", "Herman Melville")
}
});
Original Answer
DocumentDB does not support SQL parametrization yet... so you will want to sanitize your inputs to avoid unintentional exposure of data on reads (e.g. for multi-tenant applications).
That being said... the DocumentDB SQL injection attack surface area is fairly limited - as DocumentDB SQL only supports read-only queries. In other words, you do not have to worry about unintentional writes/updates/deletes in the context of DocumentDB and SQL Injection.
To answer the question as it applies to the stored procedure JavaScript file:
function simple_sp(s1) {
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();
var query = { query: "select * from Families f where f.id = #id", parameters: [{ name: "#id", value: id }] };
collection.queryDocuments(collection.getSelfLink(),
query, {},
function(res){}
);
}