Update expression for a list of maps in DynamoDB - amazon-dynamodb

I have the following DynamoDB table:
{
record_id: Decimal(10),
...,
options: [ # This is a List of maps
{option_id: 1, counter: Decimal(0), ...},
{option_id: 2, counter: Decimal(0), ...},
],
...
}
Which consists of some items, with unique record_id and the target options list. That list contains maps. In those maps, there is an option_id attribute, and I would like to access the item in the options list whose option_id equals to some target my_option_id and increment its counter.
For example, for the above example, given my_record_id=10 and my_option_id=2, I would like to update the second option item, with option_id=2, and increment its counter by 1, so this {option_id: 2, counter: Decimal(0), ...} becomes {option_id: 2, counter: Decimal(1), ...}.
I am using Python and boto3, but I imagine the syntax here is specific to DynamoDB. Here is what I have so far:
response = table.update_item(
Key={
'record_id': my_record_id,
},
UpdateExpression='SET options.#s.counter = options.#s.counter + :val',
ExpressionAttributeNames={
"#s": my_option_id
},
ExpressionAttributeValues={
':val': Decimal(1)
},
ReturnValues="UPDATED_NEW"
)

It seems the easy fix was to make options a map instead of a list, and then make the option_id the key of that map. Then my code works as expected:
response = table.update_item(
Key={
'record_id': my_record_id,
},
UpdateExpression='SET options.#s.counter = options.#s.counter + :val',
ExpressionAttributeNames={
"#s": my_option_id
},
ExpressionAttributeValues={
':val': Decimal(1)
},
ReturnValues="UPDATED_NEW"
)

Related

Sort Map<String, dynamic> in flutter dart where the first key is the field name

I have a document with fields that are generated in firebase, the field name is todays date and the value is a incremenation of a use when the user do a special thing in the app.
When i retrieve the data from firebase my Map<String, dynamic> statistics; is filled in a random order because of how data is retreived from firebase.
How can i sort the returned data on the Key value (string) so that the dates are in ascending order?
I just can not figure this out. Any hint pointers is greatly appreciated.
It's key:value bro, it doesn't exist such thing as order so it can't sort. It's a Map, just call key and it return value.
In case you really want to do this. Get keys of the map and sort, use sorted keys to create new map in order.
void main() {
var map = {"b": {}, "d": {}, "a": {}, "h": {}, "f": {}, "c": {}};
var newmap = {};
var keys = [...map.keys]..sort((a, b) => a.compareTo(b));
for (String key in keys) {
newmap[key] = map[key];
}
print("oldmap: $map");
print("newmap: $newmap");
// result
// oldmap: {b: {}, d: {}, a: {}, h: {}, f: {}, c: {}}
// newmap: {a: {}, b: {}, c: {}, d: {}, f: {}, h: {}}
}
var sortedKeys = map.keys.toList()..sort();
try this or use the below plugin
sortedmap: ^0.5.1
import 'package:sortedmap/sortedmap.dart';
main() {
var map = new SortedMap(Ordering.byValue());
map.addAll({
"a": 3,
"b": 2,
"c": 4,
"d": 1
});
print(map.lastKeyBefore("c")); // a
print(map.firstKeyAfter("d")); // b
}
import 'package:sortedmap/sortedmap.dart';
main() {
var map = new FilteredMap(new Filter(
compare: (Pair a, Pair b)=>Comparable.compare(a.value, b.value),
isValid: (Pair v) => v.key!="b",
limit: 2));
map.addAll({
"a": 3,
"b": 2,
"c": 4,
"d": 1
});
print(map.keys); // (d, a)
}

KQL - Convert Dynamic Array of Key Value to Key Value dictionary

I have a cell of a table-column that is a dynamic. This was ingested from .Net as a Dictionary, but in Kusto it looks like an array of objects, that has a property key and value:
[
{"key":"ProjectId","value":"1234"},
{"key":"ProjectName","value":"Albatros"},
{"key":"User","value":"Bond"}
]
I want to convert the contents of the cell in my Kusto query to the following dynamic:
{
"ProjectId": "1234",
"ProjectName": "Albatros",
"User": "Bond"
}
I cant figure out how to write the expression, that converts it form the array into the new dynamic format.
Can anyone point me in the right direction?
you can use a combination of mv-apply and make_bag():
print d = dynamic([
{"key": "value"},
{"ProjectId": "1234"},
{"ProjectName": "Albatros"},
{"User": "Bond"}
])
| mv-apply d on (
summarize result = make_bag(d)
)
result
{ "key": "value", "ProjectId": "1234", "ProjectName": "Albatros", "User": "Bond"}
UPDATE based on your change to the original question:
print d = dynamic([
{"key":"ProjectId","value":"1234"},
{"key":"ProjectName","value":"Albatros"},
{"key":"User","value":"Bond"}
])
| mv-apply d on (
summarize result = make_bag(pack(tostring(d.key), d.value))
)
result
{ "ProjectId": "1234", "ProjectName": "Albatros", "User": "Bond"}

How to return all the id's with common value for another field in cosmos sql api?

the cosmos doc is in this structure
{
orderNumber: 1,
productNumber:p1
},
{
orderNumber: 1,
productNumber:p2
},
{
orderNumber: 2,
productNumber:p3
}
how do I return the list of productsnumber within the same ordernumber.
for example, the result should be like
{
orderNumber:1,
products:{
p1,
p2
}
select c.orderNumber,count(c.orderNumber)
from c
group by c.orderNumber
I tried this query to get the count on ordernumber, which gives the product count, but how can we return the actual productNumber.
Thank you

Conditional if/then/else for JMESPath?

Am trying to do a simple if/then/else using JMESPath
For example: 'if the input is a string, return the string, else return the "value" property of the input'. An input of "abc" would return "abc". An input of {"value":"def"} would return "def"
With jq this is easy: if .|type == "string" then . else .value end
With JMESPath, I can get the type
type(#)
or the input:
#
or the value property:
value
but I have not found a way to combine them into an if-then-else. Is there any way to do this?
It is possible but not cleanly. The general form is to:
Make the value you are testing an array (wrap in square braces)
Apply the map function to map the filtered array to what value you want if true
At this point you have an array that is populated with one (true) item if the array filter passed, otherwise it is empty
Concat to that array one item (the false value)
Finally, take item at index 0 in this array - which will be the result of the condition
This should allow you to also derive possible transformations for both the false and true conditions
For example, if the test data is as so:
{
"test": 11
}
Depending on the value you can get either produce the results (using test data 11 and 2 as example):
"Yes, the value is 11 which is greater than 10"
OR
"No the value is 2 which is less than or equal to 10"
Like so:
[
map(
&join(' ', ['Yes, the value is', to_string(#), 'which is greater than 10']),
[test][? # > `10`]
),
join(' ', ['No the value is', to_string(test), ' which is less than or equal to 10'])
][] | #[0]
So to abstract a template:
[
map(
&<True Expression Here>,
[<Expression you are testing>][? # <Test Expression>]
),
<False Expression Here>)
][] | #[0]
people[?general.id !=100] || people
{
"people": [
{
"general": {
"id": 100,
"age": 20,
"other": "foo",
"name": "Bob"
},
"history": {
"first_login": "2014-01-01",
"last_login": "2014-01-02"
}
},
{
"general": {
"id": 101,
"age": 30,
"other": "bar",
"name": "Bill"
},
"history": {
"first_login": "2014-05-01",
"last_login": "2014-05-02"
}
}
]
}
if else condition works here

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:

Resources