dynamodb: how to increment a value in map - amazon-dynamodb

I am trying to use dynamodb to maintain a map of names with their values
eg. {"scores": {"player-a": 10}}
I also wish to use increment operator to perform atomic increments.
However, i could find very little documentation on how to use/update dynamodb maps.
Here's the python code I have so far
import boto3
ddb = boto3.client('dynamodb')
ddb.update_item(TableName='ledger', Key={'week': {'S': '06-12'}},
UpdateExpression='SET scores.player-a = scores.player-a + :val',
ExpressionAttributeValues={':val': {'N': '12'}})

DynamoDB update item uses ExpressionAttributeNames to prevent special characters in an attribute name from being misinterpreted in an expression.
Your update item consists of "player-a" as a key name which has "-" (hyphen) in it.
ddb.update_item(
TableName='ledger',
Key={
'week': {
'S': '06-12'
}
},
UpdateExpression='SET scores.#s = scores.#s + :val",
ExpressionAttributeNames={
"#s": "player-a"
},
ExpressionAttributeValues={
':val': {
'N': '12'
}
}
)

Related

Golang syntax in "if" statement with a map

I am reading a tutorial here: http://www.newthinktank.com/2015/02/go-programming-tutorial/
On the "Maps in Maps" section it has:
package main
import "fmt"
func main() {
// We can store multiple items in a map as well
superhero := map[string]map[string]string{
"Superman": map[string]string{
"realname":"Clark Kent",
"city":"Metropolis",
},
"Batman": map[string]string{
"realname":"Bruce Wayne",
"city":"Gotham City",
},
}
// We can output data where the key matches Superman
if temp, hero := superhero["Superman"]; hero {
fmt.Println(temp["realname"], temp["city"])
}
}
I don't understand the "if" statement. Can someone walk me through the syntax on this line:
if temp, hero := superhero["Superman"]; hero {
Like if temp seems nonsensical to an outsider as temp isn't even defined anywhere. What would that even accomplish? Then hero := superhero["Superman"] looks like an assignment. But what is the semicolon doing? why is the final hero there?
Can someone help a newbie out?
Many thanks.
A two-value assignment tests for the existence of a key:
i, ok := m["route"]
In this statement, the first value (i) is assigned the value stored
under the key "route". If that key doesn't exist, i is the value
type's zero value (0). The second value (ok) is a bool that is true if
the key exists in the map, and false if not.
This check is basically used when we are not confirmed about the data inside the map. So we just check for a particular key and if it exists we assign the value to variable. It is a O(1) check.
In your example try to search for a key inside the map which does not exists as:
package main
import "fmt"
func main() {
// We can store multiple items in a map as well
superhero := map[string]map[string]string{
"Superman": map[string]string{
"realname": "Clark Kent",
"city": "Metropolis",
},
"Batman": map[string]string{
"realname": "Bruce Wayne",
"city": "Gotham City",
},
}
// We can output data where the key matches Superman
if temp, hero := superhero["Superman"]; hero {
fmt.Println(temp["realname"], temp["city"])
}
// try to search for a key which doesnot exist
if value, ok := superhero["Hulk"]; ok {
fmt.Println(value)
} else {
fmt.Println("key not found")
}
}
Playground Example
if temp, hero := superhero["Superman"]; hero
in go is similar to writing:
temp, hero := superhero["Superman"]
if hero {
....
}
Here is "Superman" is mapped to a value, hero will be true
else false
In go every query to a map will return an optional second argument which will tell if a certain key is present or not
https://play.golang.org/p/Hl7MajLJV3T
It's more normal to use ok for the boolean variable name. This is equivalent to:
temp, ok := superhero["Superman"]
if ok {
fmt.Println(temp["realname"], temp["city"])
}
The ok is true if there was a key in the map. So there are two forms of map access built into the language, and two forms of this statement. Personally I think this slightly more verbose form with one more line of code is much clearer, but you can use either.So the other form would be:
if temp, ok := superhero["Superman"]; ok {
fmt.Println(temp["realname"], temp["city"])
}
As above. For more see effective go here:
For obvious reasons this is called the “comma ok” idiom. In this
example, if the key is present, the value will be set appropriately and ok
will be true; if not, the value will be set to zero and ok will be
false.
The two forms for accessing maps are:
// value and ok set if key is present, else ok is false
value, ok := map[key]
// value set if key is present
value := map[key]

Making Dynamodb update_item idempotent - List Attribute

I would like to make my update_item operation idempotent. I have an attribute of type list, and I would like to add a element to list only if not exists. I imagine that i need to use: ConditionExpression
uptd = 'SET status_pedido_disponiveis = list_append(if_not_exists(status_pedido_disponiveis, :empty_list), :my_value)'
attr={ ":my_value": {"L": [{"S": xml }]}, ":empty_list":{"L": [] } }
self.dynamodb.update_item(TableName=self.table_name, Key={'order_id':{'S': order_id}},
UpdateExpression=uptd,
ExpressionAttributeValues=attr
)
Here is the solution:
uptd = 'SET status_pedido_disponiveis = list_append(if_not_exists(status_pedido_disponiveis, :empty_list), :my_value)'
attr={ ":my_value": {"L": [{"S": xml }]}, ":empty_list":{"L": [] }, ':xml_content': {"S": xml } }
self.dynamodb.update_item(TableName=self.table_name, Key={'order_id':{'S': order_id}},
UpdateExpression=uptd,
ExpressionAttributeValues=attr,
ConditionExpression = "not contains (status_pedido_disponiveis, :xml_content)"
)

Multiple range keys in couchdb views

I've been searching for a solution since few hours without success...
I just want to do this request in couchdb with a view:
select * from database where (id >= 3000000 AND id <= 3999999) AND gyro_y >= 1000
I tried this:
function(doc) {
if(doc.id && doc.Gyro_y){
emit([doc.id,doc.Gyro_y], null);
}
}
Here is my document (record in couchdb):
{
"_id": "f97968bee9674259c75b89658b09f93c",
"_rev": "3-4e2cce33e562ae502d6416e0796fcad1",
"id": "30000002",
"DateHeure": "2016-06-16T02:08:00Z",
"Latitude": 1000,
"Longitude": 1000,
"Gyro_x": -242,
"Gyro_y": 183,
"Gyro_z": -156,
"Accel_x": -404,
"Accel_y": -2424,
"Accel_z": -14588
}
I then do an HTTP request like so:
http://localhost:5984/arduino/_design/filter/_view/bygyroy?startkey=["3000000",1000]&endkey=["3999999",9999999]&include_docs=true
I get this as an answer:
{
total_rows: 10,
offset: 8,
rows: [{
id: "f97968bee9674259c75b89658b09f93c",
key: [
"01000002",
183
],
value: null,
doc: {
_id: "f97968bee9674259c75b89658b09f93c",
_rev: "3-4e2cce33e562ae502d6416e0796fcad1",
id: "30000002",
DateHeure: "2016-06-16T02:08:00Z",
Latitude: 1000,
Longitude: 1000,
Gyro_x: -242,
Gyro_y: 183,
Gyro_z: -156,
Accel_x: -404,
Accel_y: -2424,
Accel_z: -14588
}
}
]
}
So it's working for the id but it's not working for the second key gyro_y.
Thanks for your help.
When you specify arrays as your start/end keys, the results are filtered in a "cascade". In other words, it moves from left to right, and only if something was matched by the previous key, will it be matched by the next key.
In this case, you'll only find Gyro_y >= 1000 when that document also matches the first condition of 3000000 <= id <= 3999999.
Your SQL example does not translate exactly to what you are doing in CouchDB. In SQL, it'll find both conditions and then find the intersection amongst your resulting rows. I would read up on view collation to understand these inner-workings of CouchDB.
To solve your problem right now, I would simply switch the order you are emitting your keys. By putting the Gyro_y value first, you should get the results you've described.

Query to get exact matches of Elastic Field with multile values in Array

I want to write a query in Elastic that applies a filter based on values i have in an array (in my R program). Essentially the query:
Matches a time range (time field in Elastic)
Matches "trackId" field in Elastic to any value in array oth_usr
Return 2 fields - "trackId", "propertyId"
I have the following primitive version of the query but do not know how to use the oth_usr array in a query (part 2 above).
query <- sprintf('{"query":{"range":{"time":{"gte":"%s","lte":"%s"}}}}',start_date,end_date)
view_list <- elastic::Search(index = "organised_recent",type = "PROPERTY_VIEW",size = 10000000,
body=query, fields = c("trackId", "propertyId"))$hits$hits
You need to add a terms query and embed it as well as the range one into a bool/must query. Try updating your query like this:
terms <- paste(sprintf("\"%s\"", oth_usr), collapse=", ")
query <- sprintf('{"query":{"bool":{"must":[{"terms": {"trackId": [%s]}},{"range": {"time": {"gte": "%s","lte": "%s"}}}]}}}',terms,start_date,end_date)
I'm not fluent in R syntax, but this is raw JSON query that works.
It checks whether your time field matches given range (start_time and end_time) and whether one of your terms exact matches trackId.
It returns only trackId, propertyId fields, as per your request:
POST /indice/_search
{
"_source": {
"include": [
"trackId",
"propertyId"
]
},
"query": {
"bool": {
"must": [
{
"range": {
"time": {
"gte": "start_time",
"lte": "end_time"
}
}
},
{
"terms": {
"trackId": [
"terms"
]
}
}
]
}
}
}

Meteor.find multiple values in an array

I am using auto schema to define an array field. I need to find documents where multiple specific values are contained in that array. I know I can use the $in: operator while $in: can only match either one of the value in the first array against the second array while I would need to match any record that have all value in the first array. How I can achieve this?
Schema Definition
Demands = new Mongo.Collection("demands");
var demandschema = new SimpleSchema({
ability: {type:array},
language: {type: array}});
Demands.attachSchema(demandschema);
Contents Definition
DemandsSet=[
{ability: ["laser eye", "rocky skin", "fly"], language: ["english", "latin", "hindu"]},
{ability: ["sky-high jump", "rocky skin", "fly"], language: ["english", "latin", "japanese"]},
{ability: ["rocky skin", "sky-high jump"], language: ["english", "latin", "russian"]}
];
Target Set
var TargetAbility = ["rocky skin", "fly"];
var TargetLanguage = ["english", "hindu"];
When I do a $in operation
Demands.find({ $and: [
{ ability: { $in: TargetAbility }},
{ language: { $in: TargetLanguage }}
]}).fetch();
I will return me with all records, while it is not correct, how can I perform such a find operation?
$in: is not going to work for you because it looks for any match when comparing two arrays, not that all elements of one array must be present in the other.
You can write complete javascript functions to execute the required comparisons inside the mongodb query. See $where:
For example:
Demands.find({$where:
"this.ability.indexOf(TargetAbility[0]) > -1 &&
this.ability.indexOf(TargetAbility[1]) > -1 &&
this.language.indexOf(TargetLanguage[0]) > -1 &&
this.language.indexOf(TargetLanguage[1]) > -1" });
If your candidates have other than 2 entries each then you can write a more general form of this of course.
Note that Meteor apparently does not support the function() form of $where: but that restriction may be dated.
Also note that $where: cannot take advantage of indexes so performance may not be suitable for large collections.

Resources