Updating Data Set query after parameter input in BIRT - javascript

How can I change or update a data set's query after a parameter has been passed in BIRT report designing?
Detailing:
I've got a query that looks like this:
WHERE ?
That parameter marker can hold different values, after user input parameter, it would look like this e.g.:
WHERE column_name = 1
or
WHERE column_name = 2
or even
WHERE column_name IN (1,2)
I created a Report Parameter(RP) for that Data Set Parameter(DSP) and after trying for hours, I couldn't get to change it.
I tried:
Creating all sorts of javascript expressions on both, RP and DSP
Creating a RP that would change the value of the first RP and back to previous step
Editing the Property Binding, though I couldn't figure it out how exactly it should be done.
Just to make it clear, I'm designing a report and not integrating the runtime to an existing application.
I hope this is clear enough, I'm still editing the question so if you need more information just let me know.
Thanks

Assuming that you are on an Oracle DB (other systems may behave differently) you should be aware that a bind variable (in JDBC speech: the question mark) can replace a scalar value only, e.g. a string or a number.
But you want something like a list of numbers as input.
Thus a bind variable won't help you in this case.
Probably the easiest way to achieve what you want is this:
In your query, write:
WHERE column_name in (1) -- $REPLACE_THIS$
Note that I am using a comment in the query as a marker.
Then, in the query's beforeOpen event, modify the query text like this:
// construct a comma-separated string representation of your list
// based on your report parameter (exercise left to the reader)
// var replacement = my_to_sql_csv(params["my_report_parameter"].value);
// for demonstration use:
var replacement = "1,2";
// modify the `IN` expression inside the SQL
this.queryText = this.queryText.replaceAll("(1) -- $REPLACE_THIS$", "(" + replacement + ")";
That's it.

Related

How can a linq query be converted to JavaScript array containing only values?

I have a JavaScript grid library (it creates a table on the page) that accepts a JavaScript array as input, for rendering in the grid. I'm not certain, however, how to convert a Linq-to-SQL query (against a SQL Server database) to a JavaScript array containing only values.
I tried this, but it included the table column names in the JSON key (and I don't want JSON anyway, I want a JavaScript string array, unless this can be converted to an array?):
JsonConvert.SerializeObject(query)
Example of the format I need to produce:
[1,2,3],[4,5,6]
Environment: .NET Core 3.1
edit: Here is a sample of what I've currently got, this returns the less than desirable JSON (due to the query results being so large, having a JSON key for very element is going to literally double the size of the query):
Devices Table
ID Name
1 iPhone7
2 iPhone8
3 iPhone9
Needed Array (Note: no column names)
[1, "iPhone7"],[2, "iPhone8"],[3, "iPhone9"]
Current C# code in the controller method (returns undesirable key for every element currently)
var query = db.Devices;
var formattedResult = JsonConvert.SerializeObject(query);
return Ok(formattedResult);
Technically, you could do this:
var query = db.Devices.AsEnumerable()
.Select(d => new object[]{d.ID, d.Name});
var formattedResult = JsonConvert.SerializeObject(query);
return Ok(formattedResult);
But then the code on the other end of your request is going to have to translate all those arrays back into objects.
It's rarely worthwhile to complicate your model like this in order to optimize the size of your network traffic. If you're pulling enough items over the wire to make this a performance issue, you're likely to encounter a variety of other performance issues. I would first consider other options, like implementing paging.
Did you try
var query = db.Devices.ToList();
var array = JArray.FromObject(query);
return Ok(formattedResult)

How to speed up performance of autocomplete from indexeddb database

I have jQuery autocomplete field that has to search through several thousand items, populated from an IndexedDB query (using the idb wrapper). The following is the autocomplete function called when the user begins typing in the box. hasKW() is a function that finds keywords.
async function siteAutoComplete(request, response) {
const db = await openDB('AgencySite');
const hasKW = createKeyWordFunction(request.term);
const state = "NY";
const PR = 0;
const agency_id = 17;
const range = IDBKeyRange.bound([state, PR, agency_id], [state, PR, agency_id || 9999999]);
let cursor = await db.transaction('sites').store.index("statePRAgency").openCursor(range);
let result = [];
while (cursor) {
if (hasKW(cursor.value.name)) result.push({
value: cursor.value.id,
label: cursor.value.name
});
cursor = await cursor.continue();
}
response(result);
}
My question is this: I'm not sure if the cursor is making everything slow. Is there a way to get all database rows that match the query without using a cursor? Is building the result array slowing me down? Is there a better way of doing this? Currently it takes 2-3s to show the autocomplete list.
I hope this will be useful to someone else. I removed the cursor and just downloaded the whole DB into a javascript array and then used .filter. The speedup was dramatic. It took 2300ms using the way above and about 21ms using this:
let result = await db.transaction('sites').store.index("statePRAgency").getAll();
response(result.filter(hasKW));
You probably want to use an index, where by the term index, I mean a custom built one that represents a search engine index. You cannot easily and efficiently perform "startsWith" style queries over one of indexedDB's indices because they are effectively whole value (or least lexicographic).
There are many ways to create the search engine index I am suggesting. You probably want something like a prefix-tree, also known informally as a trie.
Here is a nice article by John Resig that you might find helpful: https://johnresig.com/blog/javascript-trie-performance-analysis/. Otherwise, I suggest searching around on Google for trie implementations and then figuring out how to represent a similar data structure within an indexedDb object store or indexdDb index on an object store.
Essentially, insert the data first without the properties used by the index. Then, in an "indexing step", visit each object and index its value, and set the properties used by the indexedDb index. Or do this at time of insert/update.
From there, you probably want to open a connection shortly after page load and keep it open for the entire duration of the page. Then query against the index every time a character is typed (probably want to rate limit this call to refrain from querying more than n/second, perhaps using some kind of debounce helper function).
On the other hand, I might be a bit rusty on this one, but maybe you can create an index on the string prop, then use a lower bound that is the entered characters. A string that is lesser length than another string that contains it is present earlier in lexicographic order. So maybe it is actually that easy. You would also need to impose an upper bound that contains the entered characters thus far concatenated with some kind of sentinel value that can never realistically exist in the data, something silly like ZZZZZ.
Try this out in the browser's console:
indexedDB.cmp('test', 'tasting'); // 1
indexedDB.cmp('test', 'testing'); // -1
indexedDB.cmp('test', 'test'); // 0
You essentially want to experiment with a query like this:
const sentinel = 'ZZZ';
const index = store.index('myStore');
const bounds = IDBKeyRange.bound(value, value + sentinel);
const request = index.get(bounds);
You might need to tweak the sentinel, experiment with other parameters to IDBKeyRange.bound (the inclusive/exclusive flags), probably need to store the value in homogenized case so that the search is case insensitive, avoid every sending a query when nothing has been typed, etc.

JavaScript + MySQL: use fields as parameter in result

I'm quite new to JavaScript and I have the following issue:
I have a Node.JS server on which a webclient can connect and execute functions. One function is to look into a MySQL database and gather information.
The query is done right and I obtain the correct raw information as for example:
Here is my code:
So I correctly get the column names using the fields (fields[0].name = Count_0)variable and I am able to get the correct value using the result (result[0].Count_0 = Gray).
However, I am unable to merge the two lines in order to create the list of colors using something like this in a loop: result[0].fields[0].name = Gray
Is there an easier way to do this or not ?
Thanks,
Nicola.
In Javascript, you can use the [] operator to access a variably-named property in an object.
Instead of using result[0].fields[0].name, use
result[0][fields[0].name]
You won't get any runtime errors for accessing a property that doesn't exist, so you'll want to check whether that value is undefined before using it somewhere else.
It seems you want to get the color. If so, you can get the color by this
let color = result[0][fields[0].name];
The idea is use fields[0].name as key of result[0].
This is the breakdown of above single line.
let key = fields[0].name;
let color = result[0][key];

Qualtrics: Loop over embedded data fields?

I have a large set of embedded data fields that are called rnd1, rnd2, rnd3 etc. In a certain question block, I stored to each of these a certain value (each a different random number).
I also have a Loop and Merge question block, and in each round, I would like to access the stored data of a different field (i.e. in the 1st round I'd like to access whatever is in rnd1, in the 2nd round access rnd2 etc.) Can this be done in Qualtrics?
I tried something like:
Qualtrics.SurveyEngine.addOnload(function()
{
var trialNum = this.questionId.split('_')[0]; // getting the loop's current round number
var EDname = "rnd"+trialNum; // name of desired EF field
var rndNum = "${e://Field/" + EDname + "}"; // this is where I'd like stored the right ED value
// some more code that uses rndNum
});
but this does not work. It seems that while EDname gets the right string, I cannot access the value of that embedded field this way (though var rndNum = "${e://Field/rnd1} does work and returns the right value, so the problem seems to be in the looping strucutre).
If I cannot loop over the different fields in the JS code for some reason, is there another clever way to get that done in Qualtrics? For example, I thought it may be possible to use the different field names in the Loop and Merge section as "Field 2", but this seem to require me setting manually each and every ED field name.
Thanks.
Piped embedded data fields are resolved on the server before the page gets sent to your browser. So, it is impossible to dynamically create an embedded data field name and resolve it on the client side with JavaScript.
The way you are doing it with a loop & merge field is the best way.

Parse.com relations count

I want to query object from Parse DB through javascript, that has only 1 of some specific relation object. How can this criteria be achieved?
So I tried something like this, the equalTo() acts as a "contains" and it's not what I'm looking for, my code so far, which doesn't work:
var query = new Parse.Query("Item");
query.equalTo("relatedItems", someItem);
query.lessThan("relatedItems", 2);
It seems Parse do not provide a easy way to do this.
Without any other fields, if you know all the items then you could do the following:
var innerQuery = new Parse.Query('Item');
innerQuery.containedIn('relatedItems', [all items except someItem]);
var query = new Parse.Query('Item');
query.equalTo('relatedItems', someItem);
query.doesNotMatchKeyInQuery('objectId', 'objectId', innerQuery);
...
Otherwise, you might need to get all records and do filtering.
Update
Because of the data type relation, there are no ways to include the relation content into the results, you need to do another query to get the relation content.
The workaround might add a itemCount column and keep it updated whenever the item relation is modified and do:
query.equalTo('relatedItems', someItem);
query.equalTo('itemCount', 1);
There are a couple of ways you could do this.
I'm working on a project now where I have cells composed of users.
I currently have an afterSave trigger that does this:
const count = await cell.relation("members").query().count();
cell.put("memberCount",count);
This works pretty well.
There are other ways that I've considered in theory, but I've not used
them yet.
The right way would be to hack the ability to use select with dot
notation to grab a virtual field called relatedItems.length in the
query, but that would probably only work for me because I use PostGres
... mongo seems to be extremely limited in its ability to do this sort
of thing, which is why I would never make a database out of blobs of
json in the first place.
You could do a similar thing with an afterFind trigger. I'm experimenting with that now. I'm not sure if it will confuse
parse to get an attribute back which does not exist in its schema, but
I'll find out, by the end of today. I have found that if I jam an artificial attribute into the objects in the trigger, they are returned
along with the other data. What I'm not sure about is whether Parse will decide that the object is dirty, or, worse, decide that I'm creating a new attribute and store it to the database ... which could be filtered out with a beforeSave trigger, but not until after the data had all been sent to the cloud.
There is also a place where i had to do several queries from several
tables, and would have ended up with a lot of redundant data. So I wrote a cloud function which did the queries, and then returned a couple of lists of objects, and a few lists of objectId strings which
served as indexes. This worked pretty well for me. And tracking the
last load time and sending it back when I needed up update my data allowed me to limit myself to objects which had changed since my last query.

Categories