How to properly use Partition and Sort Key - amazon-dynamodb

I know how to use the PK and SK but in my case it's a bit different.
I basically pass some distance and I want to retrieve the vehicles that can be used.
e.g:
HTTP Request passing the distance e.g. 50km so (bycicle, car and train need to be returned)
Basically I want to retrieve the vehicles that can be used
PK | distanceMin (SK) | distanceMax | vehicleName
distance | 0 | 10 | bycicle
distance | 10 | 500 | car // cannot have SK as 0
distance | 50 | 9999 | train // cannot have SK as 0
// This will have thousands of records
The problem is that I need to do scans for this and it's cost expensive and I also cannot use the same SK (0) for car and train because it would be a duplicate.
How can I pass a distance and make a query to get all the vehicles that are inside the range distanceMin and distanceMax?
My current code
searchByDistance: async function(distance) {
const search = parseInt(distance);
let params = {
TableName: this.myTable,
ScanIndexForward: true,
ConsistentRead: false,
KeyConditionExpression: 'PK=:pkKey AND distanceMin <= :search',
ProjectionExpression: 'vehicleName',
ExpressionAttributeValues: {
':pkKey': 'distance',
':search': search,
},
FilterExpression: 'distanceMax >= :search',
};
let scanResults = [];
let items;
try {
do {
items = await this.getDbClient().query(params).promise();
(items.Items || []).forEach((item) => scanResults.push(item));
params.ExclusiveStartKey = items.LastEvaluatedKey;
} while (typeof items.LastEvaluatedKey !== 'undefined');
} catch (err) {
console.log(err, err.stack);
}
return scanResults;
},

Related

How to count subdocuments recursively

I have documents in my db that look like this:
{
"id": "1"
"entityType": "node"
"childNodes": [
{
"id": "2"
"entityType": "node"
"childNodes": [
...
]
}
]
}
As a large tree structure.
I'd like to count the total number of documents and subdocuments in my collection that are of entityType = "Node".
My attempt is to get the data one level at a time manually:
SELECT VALUE COUNT(c.id) FROM c where CONTAINS(c.id, 'a|') and c.entityType = 'node'
SELECT VALUE COUNT(l.id) FROM c JOIN l in c.childNodes where CONTAINS(c.id, 'a|') and c.entityType = 'node'
SELECT VALUE COUNT(l2.id) FROM c JOIN l in c.childNodes JOIN l2 in l.childNodes where CONTAINS(c.id, 'a|') and c.entityType = 'node'
First of all, it's hard to find a smooth(direct) way to implement your needs.Surely,the manual way you mentioned in your question works.However,if you have too many layers of JSON nesting, or it's random,your way maybe inappropriate.
I would suggest you loop the result recursively to get the count of objects which contains "entityType": "node".For example, in the cosmos db stored procedure:
function sample(prefix) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT c.childNodes FROM c where c.entityType = "node"',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
var response = getContext().getResponse();
var count = {count:1};
loopChildNodes(feed,count);
response.setBody(count);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
function loopChildNodes(array,count){
for (var i=0;i<array.length;i++){
console.log(count)
if(array[i].entityType == "node"){
count.count++;
}
if(array[i].childNodes!=null)
loopChildNodes(array[i].childNodes,count)
}
}
}
My test data:
Output:

Kotlin - group elements by a key under some conditions with new value type

I'm trying to find a way to use Kotlin collection operation to do some logic that I'm going to explain:
Let's say type Classroom contains a list of Student as a field in it, eg. classroom.getSudents() returns a list of certain studends.
Now I have a list of mixed Student that I need to group by one of its fields say major, and the value of the resultant map to be Classroom.
So I need to convert List<Student> to Map<Student.major, Classroom>
Also at some cases of major, for example for all major == chemistry, I'll need to group by another criteria, say firstname, so the keys of major chemistry would be major_firstname
Here's an example, I have a list of Student(major, firstname):
[
Student("chemistry", "rafael"),
Student("physics", "adam"),
Student("chemistry", "michael"),
Student("math", "jack"),
Student("chemistry", "rafael"),
Student("biology", "kevin")
]
I need the result to be:
{
"math" -> Classroom(Student("math", "jack")),
"physics" -> Classroom(Student("physics", "adam")),
"chemistry_michael" -> Classroom(Student("chemistry", "michael")),
"chemistry_rafael" -> Classroom(Student("chemistry", "rafael"), Student("chemistry", "rafael")),
"biology" -> Classroom(Student("biology", "kevin"))
}
I've tried groupBy, flatMapTo and associateBy but as far as I understand all of these doesn't group by a certain condition.
I will try to answer the 1st part as Roland posted an answer for the 2nd part (although I did not try it).
Assuming your classes are:
class Student(val major: String, val firstName: String)
class Classroom(val studentList: MutableList<Student>) {
fun getStudents(): MutableList<Student> {
return studentList
}
}
and with an initialization like:
val list = mutableListOf<Student>(
Student("chemistry", "rafael"),
Student("physics", "adam"),
Student("chemistry", "michael"),
Student("math", "jack"),
Student("chemistry", "rafael"),
Student("biology", "kevin"))
val classroom = Classroom(list)
val allStudents = classroom.getStudents()
you can have a result list:
val finalList: MutableList<Pair<String, Classroom>> = mutableListOf()
allStudents.map { it.major }.distinctBy { it }.forEach { major ->
finalList.add(major to Classroom(allStudents.filter { it.major == major }.toMutableList()))
}
so by the below code:
finalList.forEach {
println(it.first + "->")
it.second.getStudents().forEach { println(" " + it.major + ", " + it.firstName) }
}
this will be printed:
chemistry->
chemistry, rafael
chemistry, michael
chemistry, rafael
physics->
physics, adam
math->
math, jack
biology->
biology, kevin
It's actually the mixture of those methods which you require. There are also other ways to achieve it, but here is one possible example using groupBy and flatMap:
val result = students.groupBy { it.major }
.flatMap { (key, values) -> when (key) {
"chemistry" -> values.map { it.firstname }
.distinct()
.map { firstname -> "chemistry_$firstname" to ClassRoom(values.filter { it.firstname == firstname }) }
else -> listOf(key to ClassRoom(values))
}
}.toMap()
Assuming the following data classes:
data class Student(val major: String, val firstname: String)
data class ClassRoom(val students : List<Student>)
If you also want a map with all students grouped by major, the following suffices:
val studentsPerMajor = students.groupBy { it.major }
.map { (major, values) -> major to ClassRoom(values) }
If you then rather want to continue working with that map instead of recalculating everything from the source, it's also possible, e.g. the following will then return your desired map based on the studentsPerMajor:
val result = studentsPerMajor.flatMap { (key, classroom) -> when (key) {
"chemistry" -> classroom.students.map { it.firstname }
.distinct()
.map { firstname -> "chemistry_$firstname" to ClassRoom(classroom.students.filter { it.firstname == firstname }) }
else -> listOf(key to classroom)
}
}.toMap()

Key, Value Count in BigQuery

Implementation of the following problems in BigQuery:
I have this following dictionary in JSON format. How can I count total number of key, value inside id dictionary?
{"fil":{"property":{"id":{id_1:"a",id_2:"b",id_3:"c",id_4:"d"}}}}
The value "a" can appear in any of the ids (id_1,...,id_5) in multiple such dictionaries. Need to calculate number of times "a" has appeared in any of the ids in any of the dictionaries.
For 1., using standard SQL (uncheck the "Use Legacy SQL" box under "Show Options") you can use the comma operator to take the cross product of the table and the repeated field:
WITH MyTable AS (
SELECT STRUCT(STRUCT(ARRAY<STRUCT<key STRING, value STRING>>[('id_1', 'a'), ('id_2', 'b'), ('id_3', 'c'), ('id_4', 'd')] AS id) AS property) AS fil
UNION ALL SELECT STRUCT(STRUCT(ARRAY<STRUCT<key STRING, value STRING>>[('id_1', 'b'), ('id_3', 'e')] AS id) AS property) AS fil
UNION ALL SELECT STRUCT(STRUCT(ARRAY<STRUCT<key STRING, value STRING>>[] AS id) AS property) AS fil
UNION ALL SELECT STRUCT(STRUCT(ARRAY<STRUCT<key STRING, value STRING>>[('id_4', 'a'), ('id_2', 'c')] AS id) AS property) AS fil)
SELECT
COUNT(DISTINCT id.key) AS num_keys,
COUNT(DISTINCT id.value) AS num_values
FROM MyTable t, t.fil.property.id AS id;
+----------+------------+
| num_keys | num_values |
+----------+------------+
| 4 | 5 |
+----------+------------+
Using legacy SQL, you can accomplish something similar using EXACT_COUNT_DISTINCT (you probably won't need to flatten), although it's harder to set up an inline example.
For 2., you can apply a similar approach using standard SQL of flattening and then counting the number of occurrences of "a" with COUNTIF(id.value = "a"). In legacy SQL, alternatively, you can use COUNT(t.fil.property.id.value = "a").
Assuming you have your dictionaries stored in Your Table as string in field named json
The key for answer is below query.
It parses json field and extract all the key/value pair along with their parent (dictionary name)
SELECT parent, key, value
FROM JS((
SELECT json FROM
(SELECT '{"fil":{"property":{"id":{"id_1":"a","id_2":"b","id_3":"c","id_4":"d"}}}}' AS json),
(SELECT '{"fil":{"property":{"type":{"id_1":"x","id_2":"a","id_3":"y","id_4":"z"}, "category":{"id_1":"v","id_2":"w","id_3":"a","id_4":"b"}}}}' AS json)
),
json, // Input columns
"[{name: 'parent', type:'string'}, // Output schema
{name: 'key', type:'string'},
{name: 'value', type:'string'}]",
"function(r, emit) { // The function
x = JSON.parse(r.json);
processKey(x, '');
function processKey(node, parent) {
Object.keys(node).map(function(key) {
value = node[key].toString();
if (value !== '[object Object]') {
emit({parent:parent, key:key, value:value});
} else {
if (parent !== '' && parent.substr(parent.length-1) !== '.') {parent += '.'};
processKey(node[key], parent + key);
};
});
};
}"
)
Result of above query is as below
parent key value
fil.property.id id_1 a
fil.property.id id_2 b
fil.property.id id_3 c
fil.property.id id_4 d
fil.property.type id_1 x
fil.property.type id_2 a
fil.property.type id_3 y
fil.property.type id_4 z
fil.property.category id_1 v
fil.property.category id_2 w
fil.property.category id_3 a
fil.property.category id_4 b
From there, you can easily get both answers:
Q1: How can I count total number of key, value inside "id" (each) dictionary
SELECT parent, COUNT(1) AS key_value_pairs
FROM JS((
SELECT json FROM
(SELECT '{"fil":{"property":{"id":{"id_1":"a","id_2":"b","id_3":"c","id_4":"d"}}}}' AS json),
(SELECT '{"fil":{"property":{"type":{"id_1":"x","id_2":"a","id_3":"y","id_4":"z"}, "category":{"id_1":"v","id_2":"w","id_3":"a","id_4":"b"}}}}' AS json)
),
json, // Input columns
"[{name: 'parent', type:'string'}, // Output schema
{name: 'key', type:'string'},
{name: 'value', type:'string'}]",
"function(r, emit) { // The function
x = JSON.parse(r.json);
processKey(x, '');
function processKey(node, parent) {
Object.keys(node).map(function(key) {
value = node[key].toString();
if (value !== '[object Object]') {
emit({parent:parent, key:key, value:value});
} else {
if (parent !== '' && parent.substr(parent.length-1) !== '.') {parent += '.'};
processKey(node[key], parent + key);
};
});
};
}"
)
GROUP BY parent
result is
parent key_value_pairs
fil.property.id 4
fil.property.type 4
fil.property.category 4
Q2: Need to calculate number of times "a" (any value) has appeared in any of the ids in any of the dictionaries.
SELECT value, COUNT(1) AS value_appearances
FROM JS((
SELECT json FROM
(SELECT '{"fil":{"property":{"id":{"id_1":"a","id_2":"b","id_3":"c","id_4":"d"}}}}' AS json),
(SELECT '{"fil":{"property":{"type":{"id_1":"x","id_2":"a","id_3":"y","id_4":"z"}, "category":{"id_1":"v","id_2":"w","id_3":"a","id_4":"b"}}}}' AS json)
),
json, // Input columns
"[{name: 'parent', type:'string'}, // Output schema
{name: 'key', type:'string'},
{name: 'value', type:'string'}]",
"function(r, emit) { // The function
x = JSON.parse(r.json);
processKey(x, '');
function processKey(node, parent) {
Object.keys(node).map(function(key) {
value = node[key].toString();
if (value !== '[object Object]') {
emit({parent:parent, key:key, value:value});
} else {
if (parent !== '' && parent.substr(parent.length-1) !== '.') {parent += '.'};
processKey(node[key], parent + key);
};
});
};
}"
)
GROUP BY value
value value_appearances
a 3
b 2
c 1
d 1
x 1
y 1
z 1
v 1
w 1
As other answers were to hard for me I made regular expression that works for string:int dict
SELECT
*, REGEXP_EXTRACT_ALL(my_dict_column, r'"(\w+": \d+)') as keys
FROM test.test_table
From that you can do keys, values and etc

Assign "and userName in('kuldeep')" to variable and add to query then execute

I have some code like:
declare #Condition nvarchar(50), --value 'and user_name in ('deep')
select * from table where id = 10
After 10 I want to put #Condition value. How to assign and put it?
Use SET #local_variable
SET { { #local_variable = expression }
| { #cursor_variable = { #cursor_variable | cursor_name
| { CURSOR [ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
[ TYPE_WARNING ]
FOR select_statement
[ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] }
]
}
} }
}
To use a string that contains SQL as part of a query you need the EXECUTE statement.
DECLARE #Condition NVARCHAR(50) = 'AND user_name IN (''deep'')';
EXECUTE( 'SELECT * FROM table WHERE id = 10 ' + #Condition );

summing up values in an array

How do I sum up the values for my array? Here's the output if I trace my array (I couldn't find the actionscript equivalent of PHP's print_r function):
for(var k:int=0; k<tempAC.length; k++){
trace(tempAC[k].name);
trace(tempAC[k].value);
trace('-----------');
}
__OUTPUT__
Bob
3
-----------
Mary
5
-----------
Bob
12
-----------
Mary
1
How do I construct an array that would sum up Bob & Mary's respective values?
ie the Output would be:
Bob
15
------------
Mary
6
------------
I've got (where I try += to sum the values):
for(var k:int=0; k<tempAC.length; k++){
newAC['name']=tempAC[k].name;
newAC['value']+=tempAC[k].value;
}
var tempAC:Array = [
{name: "Bob", value: 3},
{name: "Mary", value: 5},
{name: "Bob", value: 12},
{name: "Mary", value: 1}
];
/**
* Combines values in objects that have identical names
* #param ar The array to assess
*/
function combine(ar:Array):Array
{
var hold:Array = [];
var back:Array = [];
var i:Object;
for each(i in ar)
{
if(!hold[i.name]) hold[i.name] = i.value;
else hold[i.name] += i.value;
}
var j:String;
for(j in hold)
{
back.push({name: j, value: hold[j]});
}
return back;
}
var list:Array = combine(tempAC);
var i:Object;
for each(i in list)
{
trace(i.name + ": " + i.value);
}
Output:
Bob: 15
Mary: 6
for(var k:int=0; k<tempAC.length; k++){
newAC[tempAC[k].name]+=tempAC[k].value;
}
That way you sum each name separately, regardless how many names u have there.
To see output:
(what ever is your print method, I'll call it echo)
echo newAC['THE NAME YOU WANT'];
b.t.w I have no idea about Flash, but the concept is good, and the syntax (except the echo) is also good.
Take a look at creating an Associative Array with a String Key. Read the article and it should get you started.

Resources