Azure Stream Analytics: Get Array Elements by name - sql

I was wondering if it is possible for me to get the elements of the array by the name of property than the position. For example, this is my incoming data:
{
"salesdata": {
"productsbyzone": {
"zones": [{
"eastzone": "shirts, trousers"
},
{
"westzone": "slacks"
},
{
"northzone": "gowns"
},
{
"southzone": "maxis"
}
]
}
}
}
I intend to move this to a SQL database and I have columns within the database for each zone. The problem is that the order of different zones changes within each json. I was successfully using the following query until I realized that the position of the zones changes within each json:
WITH
salesData AS
(
SELECT
(c.salesdata.productsbyzone.zone,0) as eastzone,
(c.salesdata.productsbyzone.zone,1) as westzone,
(c.salesdata.productsbyzone.zone,2) as northzone,
(c.salesdata.productsbyzone.zone,3) as sourthzone,
FROM [sales-data] as c
)
SELECT
eastzone.eastzone as PRODUCTS_EAST,
westzone.westzone as PRODUCTS_WEST,
northzone.northzone as PRODUCTS_NORTH,
southzone.southzone as PRODUCTS_SOUTH
INTO PRODUCTSDATABASE
FROM salesData
Need a way to reference these fields by the name rather than by the position.

I recommend a solution: Use the JavaScript UDF in the azure stream job to complete the columns sort.
Please refer to my sample:
Input data(upset the order):
{
"salesdata": {
"productsbyzone": {
"zones": [{
"westzone": "slacks"
},
{
"eastzone": "shirts, trousers"
},
{
"northzone": "gowns"
},
{
"southzone": "maxis"
}
]
}
}
}
js udf code:
function test(arg) {
var z = arg;
var obj = {
eastzone: "",
westzone: "",
northzone: "",
southzone: ""
}
for(var i=0;i<z.length;i++){
switch(Object.keys(z[i])[0]){
case "eastzone":
obj.eastzone = z[i]["eastzone"];
continue;
case "westzone":
obj.westzone = z[i]["westzone"];
continue;
case "northzone":
obj.northzone = z[i]["northzone"];
continue;
case "southzone":
obj.southzone = z[i]["southzone"];
continue;
}
}
return obj;
}
You can define the order you want in the obj parameter
SQL:
WITH
c AS
(
SELECT
udf.test(jsoninput.salesdata.productsbyzone.zones) as result
from jsoninput
),
b AS
(
SELECT
c.result.eastzone as east,c.result.westzone as west,c.result.northzone as north,c.result.southzone as south
from c
)
SELECT
b.east,b.west,b.north,b.south
INTO
jaycosmos
FROM
b
Output:
Hope it helps you.

You can use GetArrayElement to return array element then access to each property. Please refer the below query
WITH
salesData AS
(
SELECT
GetArrayElement(zones,0) as z
FROM [sales-data] as s
)
SELECT
z.eastzone
z.westzone
z.northzone
z.southzone
FROM PRODUCTSDATABASE
FROM salesData

Related

In Redisgraph, how can I store the numeric value of 0?

I'm using Redisgraph. I'm using this query:
MERGE (p:Person { age: 0 } )
RETURN p
But what I get is age: "".
If I query:
MERGE (p:Person { age: 12 } )
RETURN p
This correctly store age: 12 (without quotes).
How can I store the numeric value of 0?
Thank you!
A minimal example which create a node with an attribute with the value 0 and retrieves it using redisgraph.js
const RedisGraph = require("redisgraph.js").Graph;
let graph = new RedisGraph("G");
(async () =>{
await graph.query("CREATE (:L {v:0})");
let res = await graph.query("MATCH (a) RETURN a, a.v");
while (res.hasNext()) {
let record = res.next();
console.log(record.get("a"));
console.log(record.get("a.v"));
}
graph.deleteGraph();
graph.close();
})();
Output:
Node { id: 1, label: undefined, properties: { v: 0 } }
0
#albertoSpinella would you mind sharing a reproducible snippet?

How to Add a new field to nested jsonb object in Node-Postgres using parameters?

There is a table A and jsonb field 'context', it looks like:
{
"variable": {},
"other_stuff": {}
}
I need to add a new property to 'varialbe' every time i run query. So It should do smth like:
query1
{
"variable": {
"var1": "var1Value"
},
"other_stuff": {}
}
query2
{
"variable": {
"var1": "var1Value1",
"var2": "var1Value2"
},
"other_stuff": {}
}
And if variable already has this field, it should replace it.
I run this sql, and it works:
let sql = UPDATE chatbots.A SET context = context || jsonb_set(context, '{variable, var1}', 'var1Value1')
It works but when i need to replace 'var1' and 'var1Value1' by parameters ($1 and $2) - it doesn't work (in node-postgres)
I realized that i can replace second parameter by
to_jsonb($2::text)
But what should i do with the first one?
My javascript code
async setUsersVariables(params: {users: ChatUser[], variable_name: string, variable_value: string}) {
const {users, variable_name, variable_value} = params
if (!users.length) return false
let sql = "UPDATE chatbots.A SET context = context || jsonb_set(context, '{variable, $1}', to_jsonb($2)::text) WHERE chat_user_id IN ( "
const parsedUsers = users.map(e=> e?.chat_user_id)
let sqlParams: any[] = [variable_name, variable_value]
let idx = 3;
({ sql, idx, params: sqlParams } = addSqlArrayParams(sql, parsedUsers, idx, sqlParams));
sql += ` RETURNING chat_id, chat_user_id, platform, platform_user_id`;
const filteredUsers: any = (await this.pool.query(sql, sqlParams)).rows
return filteredUsers
}

Store Address book contact in sqlite titanium

So i am building an application that takes contact information from the address book and stores it into a Titanium Model for use later on in the user journey.
All other information is storing and returning correctly however the image of the contact always comes back blank for some reason.
The code for storing the address book information is as follows
if (Ti.Contacts.contactsAuthorization == Ti.Contacts.AUTHORIZATION_AUTHORIZED){
var people = Titanium.Contacts.getAllPeople();
var totalContacts = people.length;
var addressbook = [];
Alloy.Collections.contactsModel.numberOfContacts();
Ti.API.info(numberOfContacts);
if(totalContacts > 0){
var phoneContacts = [];
for (var index = 0; index < totalContacts; index++){
var person = people[index];
phoneContacts.push({
name:person.fullName,
phoneNumber:person.phone,
profileImage:person.image,
contactID:person.identifier
});
}
Alloy.Collections.contactsModel.reset(phoneContacts);
Alloy.Collections.contactsModel.each(function(_m) {
_m.save();
});
}
} else if (Ti.Contacts.contactsAuthorization == Ti.Contacts.AUTHORIZATION_UNKNOWN){
Ti.Contacts.requestAuthorization(function(e){
//Authorization is unknown so requesting for authorization
if (e.success) {
} else {
}
});
} else {
}
}
The model definition is as follows
exports.definition = {
config: {
columns: {
"friendID": "INTEGER PRIMARY KEY AUTOINCREMENT",
"contactID": "string",
"name": "string",
"phoneNumber": "string",
"emailAddress": "string",
"profileImage": "blob"
},
adapter: {
type: "sql",
collection_name: "contactsModel",
idAttribute:"friendID"
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// extended functions and properties go here
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
collection.trigger('sync');
},
}
}
*/
});
return Collection;
}
};
The image was working fine when collecting it from the address book and putting it into a list view. However when it's saved and then i attempt to retrieve it and put it into a list view where the problem occurs.
Thanks guys.
Something to consider is not to put all the information in the database. The reason is that when it changes on the device, those changes will not reflect in the records you've stored.
Here's how I approach it:
var db = Ti.Database.open( 'person' );
db.execute( "CREATE TABLE IF NOT EXISTS people( " +
"id INTEGER PRIMARY KEY, identifier TEXT, pid INTEGER);" );
var person = db.execute( 'SELECT id, identifier, pid FROM people' );
while( person.isValidRow( ) ) {
var contact,
contact_id;
if( OS_IOS ) {
contact_id = person.fieldByName( 'identifier' );
}
if( OS_ANDROID ) {
contact_id = person.fieldByName( 'pid' );
}
contact = Ti.Contacts.getPersonByIdentifier( contact_id );
var p_image = contact.image || "/images/user";
...
}
Essentially, I store the contact's ID in the database and then use that identifier to retrieve the user's info.
Note that the user's record does not always have an image, so it is a good idea to provide a default.

dojo 1.8: populate select box with items from database including null values

Hi I just want to populate the select or comboBox.
I am able to populate both with the searchAttr to any string from JSON. But not so when there are null values.
JSON string :
[{"batch":"0000001000"},{"batch":"0000"},{"batch":""},{"batch":null}]
dojo code:
var selBatch = new ComboBox //located at the left side of the page and it is the second select box in a row
(
{ id:'ID_selBatch',
value:'',
searchAttr:'batch',
placeHolder:'Select...',
style:{width:'150px'},
}, 'node_selBatch'
);
on(selTest, 'change', function(valueCard)
{
var selectedTest = this.get('displayedValue');
var selBatch = registry.byId('ID_selBatch');
console.debug('Connecting to gatherbatches.php ...');
request.post('gatherbatches.php',
{ data:{nameDB:registry.byId('ID_selPCBA').value, nameCard : valueCard},
handleAs: "json"}).then
(
function(response)
{
var memoStore2 = new Memory({data:response});
selBatch.set('store', memoStore2);
selBatch.set('value','');
console.debug('List of batches per Test is completed! Good OK! ');
},
function(error)
{
alert("Batch's Error:"+error);
console.debug('Problem: Listing batches per Test in select Test is BAD!');
}
);
selBatch.startup();
});
Error :
TypeError: _32[this.searchAttr] is null
defer() -> _WidgetBase.js (line 331)
_3() -> dojo.js (line 15)
_f.hitch(this,fcn)(); -> _WidgetBase.js (line 331)
Please advise though it might strange to have null values populate in the select box but these null values are related to data in other columns in database, so the null values included so that I can apply mysql scripts later. Or do you have other better suggestion?
Clement
You can create a QueryFilter as in this jsfiddle to achieve what you want, but it might be simpler to have two data items. Your original model with possibly null batch properties, and the model you pass to the store which is used by the ComboBox.
But anyway, this can work:
function createQueryFilter(originalQuery, filter) {
return function () {
var originalResults = originalQuery.apply(this, arguments);
var results = originalResults.filter(filter);
return QueryResults(results);
};
}
and
var memoStore = new Memory({
data: data
});
memoStore.query = createQueryFilter(memoStore.query, function (item) {
console.log(item);
return !!item.batch;
});
and the dummy data:
function createData1() {
var data = [];
for (var i = 0; i < 10; i++) {
data.push({
name: "" + i,
batch: (0 === i % 2) ? "batch" + i : null
});
}
return data;
}
Screenshot. The odd numbered batch items are null in my example.

How i can change the sort order (from default ASC to DESC) if i use custom sorting function in DataTables?

I need perform sorting by date (dd.mm.YYYY H:i:s) in DataTables grid.
I already found DataTables sorting plugin and it works well - but i cant understand how i can change default sort order to descending for sorting plugin results.
I initialize datatables with this code:
$('.dt_table').dataTable( {
"sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>",
"sPaginationType": "bootstrap",
"aoColumns": [
{ "sType": "date-euro" },
null,
null,
null,
null,
null,
null
],
"iDisplayLength": 25,
"oLanguage": {
"sUrl": "/js/dt_ru.txt"
},
"fnDrawCallback": function() {
$(".editable").editable();
}
} );
And the code of sorting plugin is here:
jQuery.extend( jQuery.fn.dataTableExt.oSort, {
"date-euro-pre": function ( a ) {
if ($.trim(a) != '') {
var frDatea = $.trim(a).split(' ');
var frTimea = frDatea[1].split(':');
var frDatea2 = frDatea[0].split('.');
var x = (frDatea2[2] + frDatea2[1] + frDatea2[0] + frTimea[0] + frTimea[1] + frTimea[2]) * 1;
} else {
var x = 10000000000000; // = l'an 1000 ...
}
return x;
},
"date-euro-asc": function ( a, b ) {
return a - b;
},
"date-euro-desc": function ( a, b ) {
return b - a;
}
} );
Use aaSorting option to specify the sorting by: http://datatables.net/ref#aaSorting.
$('.dt_table').dataTable( {
"aaSorting": [[0, 'desc']]
} );