I'd like to know how they did it in the edit page of the datastore viewer and any help would be much appreciate. Seems pretty simple but can't figure it out. Here's a screenshot to show exactly what I mean.
The Key class has a kind and (name or id), and also a parent, which will be null or another key.
Starting from the key for an entity, you can print the kind and the id, then look for the parent, print its kind and id, then look for its parent, print the kind and id, etc.
See https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/Key
The string encoded Key does indeed contain the kind and id of itself and all its ancestors. There is no problem with looping server-side on the parent field until it is null (it's basically a string + objects manipulation, no query to the datastore is involved), to create the breadcrumb.
I don't know if it has been done client-side in JS, but it should be possible as it is basically a base64 encoding. See function Encode() in https://github.com/golang/appengine/blob/master/datastore/key.go for the algorithm.
This online tool decodes and encode keys : http://datastore-key.appspot.com . It also works as a service with JSON output. The Go code server-side does not issue datastore queries.
The Java answer is probably this:
https://cloud.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/KeyFactory#stringToKey(java.lang.String)
This gives you a Key from an encoded representation, which you can then query for kind, namespace, id, parent and appId, which allows similar processing than in the python answer mentioned in a comment above.
As an example, the following code fragment remaps a key that has one parent and comes originally from another GAE application:
String key = "sflkjsadfliasjflkhsa"; // replace this by a real key
// a not very elegant way to get the current app id
String appId = KeyFactory.createKey("dummy", 1).getAppId();
// here, the key is converted from an encoded String to a key object
Key keyObj = KeyFactory.stringToKey(key);
String oldAppId = keyObj.getAppId();
// if the app id is different, we have to convert the key
if (!appId.equals(oldAppId)) {
// creeate a new key with parent having the correct app id
Key parentKey = keyObj.getParent();
Key newParentKey = KeyFactory.createKey(parentKey.getKind(), parentKey.getId());
Key newKeyObj = KeyFactory.createKey(newParentKey, keyObj.getKind(), keyObj.getId());
// convert the key back to a String replacing the original one
String newKey = KeyFactory.keyToString(newKeyObj);
// replace this by a call to your logger
Log.warn(getClass(), "remapped key: appId: " + oldAppId + " -> " + appId + " oldKey: " + key + " -> " + newKey);
key = newKey;
}
Related
I've seen a lot of examples of using UpdateExpression to update attributes using the updateItem method. However, I still don't understand how to update multiple attributes in DynamoDB at the same time dynamically.
I am trying to update AND rename multiple attributes in the same updateItem call.
I understand that this requires a REMOVE of the old name and a SET of the new name. I have these names in hashedId's of objects, but won't have them until runtime. So my question is how do I use UpdateExpression with variables and not a hard-coded String?
All the examples I have seen use hard-coded UpdateExpressions.
can't update item in DynamoDB
Dynamo DB : UpdateItemSpec : Multiple Update Expression - Not Working
DynamoDB update Item multi action
How to rename DynamoDB column/key
I am working in Java.
It seems very odd to me that I haven't been able to find an example of this... which leads me to believe I am doing something wrong.
Thanks for the help!
You have to build the update expression string dynamically based on the attribute names and values that you receive at runtime. I do exactly this. I'm not working in Java, but here is some pseudo code (with a Ruby bias) example for you that dynamically builds the update expression string, the expression attribute names hash, and the expression attribute values hash. You can then plug in these 3 things into the update_item method:
update_exp_set = [] //array of remove expression snippets
update_exp_remove = [] //array of update expression snippets
exp_attribute_names = {} //hash of attribute names
exp_attribute_values = {} //hash of attribute values
// Iterate through all your fields and add things as needed to your arrays and hashes.
// Two examples are below for a field with the name <fieldName> and value <fieldValue>.
// You'll need to convert this to Java and update it to make sense with the AWS Java SDK.
// For a given field that needs to be updated:
update_exp_set << "#<fieldName> = :fieldValue" //add to array of set expression snippets
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
exp_attribute_values[":<fieldValue>"] = "<fieldValue>" //add to hash of attribute values
// For a given field that needs to be removed:
update_exp_remove << "#<fieldName>"
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
// Use your snippets to create your full update expression:
update_exp_set_clause = ""
update_exp_remove_clause = ""
if update_exp_set.length != 0 //check if you have something to set
update_exp_set_clause = "SET " + update_exp_set.join(',')
end
if update_exp_remove.length != 0 //check if you have something to remove
update_exp_remove_clause = "REMOVE" + update_exp_remove.join(',')
end
final_update_exp = update_exp_set_clause + " " + update_exp_remove_clause
Does this help?
Is there any way to convert the string below to a list?
This string is retrieved after scanning a QR code.
CashRequest{
orderid='0',
user_id='nvHt2U5RnqUwXB4ZK37Zn1DXPV82',
userName='username',
userEmail='whateveremailthisis#email.blabla',
fullName='full name',
phoneNumber=0,
totalCash='$304.00',
totalRV='$34.00',
foods=[
Order{
userID='nvHt2U5RnqUwXB4ZK37Zn1DXPV82',
ProductID='-LMDiT7klgoXU8bQEM-4',
ProductName='Coke',
Quantity='4',
Price='1',
RedemptionPrice='10',
RedemptionValue='1'},
Order{
userID='nvHt2U5RnqUwXB4ZK37Zn1DXPV82',
ProductID='1000',
ProductName='Kunau Ring Ring Pradu',
Quantity='3',
Price='100',
RedemptionPrice='10',
RedemptionValue='10'
}
]
}
The desired output is to store it in firebase realtime database as below :
Well you have a few options. Since it is newline between values, you could use simple newline reads and compare if it starts with "reserved word that you are looking for" then substring from there, but that can get messy and a lot of bloat code.
The simplest way would be to do the known replace first.
Make a method that replaces all bad json keys with quote surrounded json keys like:
val myJsonCorrected = yourStringAbove.replace("Order", "\"Order"\")
repeat for all known entities until you have made it into valid json. Single ticks are fine for the values, but the keys need quotes as well.
Then simply create an object that matches the json format.
class CashRequestModel{
#SerializableName("orderid")
var orderID: Int? = null
etc.....
#SerializableName("foods")
var myFoods: ArrayList<OrderModel>? = null
}
class OrderMode {
#SerializableName("userID")
var userID: String? = null
#SerializableName("ProductID")
var userID: String? = null
etc..
}
Then simply convert it to JSON
val cashRequest = getGson().fromJson(cleanedUpJson, classTypeForCashRequest);
and your done. Now just use the list. Of course it would be better if you could get valid JSON without having to clean it up first, but it looks like the keys are known and you can easily code string replaces to fix the bad json before casting it to object that matches the structure.
Hope that helps.
I am trying to query objects with a list of keys and a refference key as follows:
//s is a datastore key
Query q2 = pm.newQuery(Stream_Result.class,":p.contains(key) && stream == " + KeyFactory.keyToString(s));
ArrayList<List<Stream_Result> stream_r_list = (List<Stream_Result>) q2.execute(Arrays.asList(cr.getStreamResults().toArray()))
It works perfectly until a key with the character "-" is introduced.
if s is somthing like ag1zfmVkaW5zdHV0aW9ucg4LEgZTdHJlYW0Y then it executes fine. But if the key is something like ag1zfmVkaW5zdHV0aW9ucg4LEgZTdHJlYW0Y-dIBDA I get an exception:
org.datanucleus.store.appengine.query.DatastoreQuery$UnsupportedDatastoreFeatureException:
Right side of expression is composed of unsupported components. Left: org.datanucleus.query.expression.VariableExpression, Op: - , Right: VariableExpression{dIBDA}
How can I work arround this?
I'm working with the low-level datastore API. I've created an entity like this:
Entity entity = new Entity("Error");
entity.setProperty("description", "foo");
In the datastore viewer, I ses this:
Key Write Ops ID/Name description
----------------------------------------------
ahN0c... 4 259 foo
So the ID/Name field will be generated for me automatically since I'm not supplying anything in the Entity constructor. It generates an "ID" instead of a "Name", which is a number rather than an opaque string (like the "Key" value).
Is there a way to have the datastore generate a random "Name" instead of an "ID" for the Entity's "ID/Name" field?
I ask because if I share this ID with third parties, they could start to figure out roughly how many Error instances I have in my system. I'd rather give them an opaque string for the lookup ID, similar to what's in the auto-generated "Key" field. But I don't see a way to do this.
Thanks
For a similar task I used UUID to create a random string.
String uuid = UUID.randomUUID().toString();
You can use com.google.appengine.api.datastore.KeyFactory, combining the answer from #Devolus, it would look like
final Key key = KeyFactory.createKey("Error", UUID.randomUUID().toString());
final Entity e = new Entity(key);
You could even pass around the String representation of your Entitie's key via KeyFactory.keyToString(key) , may be after an encrypting depending on your security needs.
I have a result of a db query in java.sql.ResultSet that needs to be converted to hierarchical data structure. It looks a bit like so:
name|version|pname|code|count
n1|1.1|p1|c1|3
n1|1.1|p1|c2|2
n1|1.1|p2|c1|1
n1|1.2|p1|c1|0
n2|1.0|p1|c1|5
I need that converted into a hierarchical data structure:
N1
+ 1.1
+ p1
+ c1(3)
+ c2(2)
+ p2
+ c1(1)
+ 1.2
+ p1
+ c1(0)
N2
+ 1.0
+ p1
+ c1(5)
So my data structure can look something like this
Name {
String name
List<Version> versions
}
Version {
String version
List<PName> pnames
}
PName {
String pName
List<CodeCount> codeCounts
}
CodeCount {
String code
Integer count
}
Anyone have suggestions/code snippets on the best way to do this?
There are a few ways, and how you do it depends on how robust your solution needs to be.
One would be to just write a couple of objects that had the attributes in the database. Then you could get the result set, and iterate over it, creating a new object each time the key field (for example, "name") changed, and adding it to a list of that object. Then you'd set the attributes appropriately. That is the "quick and dirty" solution.
A slightly more robust way would be to use something like Hibernate to do the mapping.
If you do decide to do that, I would also suggest redoing your tables so that they accurately reflect your object structure. It may not be needed if you just want a fast solution. But if you are seeking a robust solution for commercial or enterprise software, it's probably a good idea.