I have a table (Profile) with a Hash key (id), and I have a GSI on name, and a range key on country.
I would like to create a DAO method which would fetch me all the records with a given value for name and country, something like this: List getProfileWithNameAndCountry(name, country);
Initially I was just searching the records using only name (GSI) using the following code and it worked perfectly:
Profile profile = new Profile();
profile.setCountry("name");
DynamoDBQueryExpression<Profile> queryExpression = new DynamoDBQueryExpression<Profile>()
.withIndexName("name-index")
.withHashKeyValues(profile)
.withConsistentRead(false);
But now I want to search using both name (GSI) and country (range key). I tried modifying the above code to this and it failed with an exception:
Profile profile = new Profile();
profile.setCountry("name");
Condition countryCondition = new Condition()
.withComparisonOperator(ComparisonOperator.EQ.toString())
.withAttributeValueList(new AttributeValue().withS(country));
DynamoDBQueryExpression<Profile> queryExpression = new DynamoDBQueryExpression<Profile>()
.withIndexName("name-index")
.withHashKeyValues(profile)
.withRangeKeyCondition("country", countryCondition)
.withConsistentRead(false);
I am really new to DynamoDB and I am not able to figure out how I can achieve this in java.
Any help would be really appreciated.
You can't combine hash key from the GSI with the range key of the table.
You need to create the GSI with both a hash and range key.
Related
1.- Create object id
// Allocate a key for the conference -- let App Engine allocate the ID
final Key<Conference> conferenceKey = factory().allocateId(profileKey, Conference.class);
// Get the Conference Id from the Key
final long conferenceId = conferenceKey.getId();
2.- Create objeto, add id
// Create Conference
Conference conference = new Conference(conferenceId,userId,conferenceForm);
3.- Save object:
// Save Conference and Profile Entities
ofy().save().entities(profile,conference).now();
ofy().save().entity(conference).now();
4.- Error, multiples times using same id (Datastore google)
Note: Same objects created with same ANDROID_CLIENT_ID (release mode)
What you are seeing is correct. Your screenshot shows 2 entities with ID=1, but with different Parents (ancestor paths).
A Datastore Key is formed from its full ancestor path and it is the Key that is unique - not the ID/Name. The ID/Name is only unique within the scope of its Parent. If an entity has no ancestor, then you would expect the ID to be unique.
This page gives a good overview of Keys.
I have the key id of the entity I want to delete, but when trying to delete using get_by_id, it is not deleting the entity (it's not doing anything).
The numerical id (I assume its a number, not a string) is stored in the 'key' get data:
d = car_database.Car()
ident = self.request.get('key')
d.get_by_id(ident).delete()
The id in this instance is: 5659313586569216
Thanks for the help
This is incorrect. Please look at the documentation on deleting entities - https://cloud.google.com/appengine/docs/python/ndb/entities#deleting_entities - it's pretty clear what you should be doing.
In your case you should be
ident = self.request.get('key')
d = car_database.Car.get_by_id(ident)
if d:
d.key.delete()
Note that get_by_id is in fact a classmethod so you don't need to instantiate in instance of Car to use it.
And delete is a method of the Key, not of Model.
Ok so I have an application that uses GAE and consequently the datastore.
Say I have multiple companies A, B and C and I have within each company Employees X,Y and Z. The relationship between a company and employee will be OneToMany, with the company being the owner. This results in the Company Key being of the form
long id = 4504699138998272; // Random Example
Key CompanyKey = KeyFactory.createKey(Company.class.getSimpleName(), id);
and the employee key would be of the form
long id2 = 5630599045840896;
Key EmployeeKey = KeyFactory.createKey(CompanyKey,Employee.class.getSimpleName(),id2);
all fine and well and there is no problem, until in the front end, during jsp representation. Sometimes I would need to generate a report, or open an Employees profile, in which case the div containing his information would get an id as follows
<div class="employeeInfo" id="<%=employee.getKey().getId()%>" > .....</div>
and this div has an onclick / submit event, that will ajax the new modifications to the employee profile to servelet, at which point I have to specify the primary key of the employee, (which I thought I could easily get from the div id), but it didnt work server side.
The problem is I know the Employees String portion of the Key and the long portion, but not the Parent key. To save time I tried this and it didnt work
Key key = KeyFactory.creatKey(Employee.class.getSimpleName(); id);
Employee X = em.find(Employee.class,key);
X is always returned null.
I would really appreciate any idea of how to find or "query" Entities by keys without knowing their parents key (as I would hate having to re-adjust Entity classes)
Thanks alot !!
An Entity key and its parents cannot be separated. It's called ancestor path, a chain composed of entity kinds and ids.
So, in your example ancestor paths will look like this:
CompanyKey: ("Company", 4504699138998272)
EmployeeKey: ("Company", 4504699138998272, "Employee", 5630599045840896)
A key composed only of ("Employee", 5630599045840896) is a completely different one comparing to the EmployeeKey even though both keys end with the same values. Think of concatenating elements into a single "string" and comparing final values, they will never match.
One thing you can do is use encoded keys instead of their id values:
String encodedKey = KeyFactory.keyToString(EmployeeKey);
Key decodedKey = KeyFactory.stringToKey(encodedKey);
decodedKey.equals(EmployeeKey); // true
More about Ancestor Paths:
https://developers.google.com/appengine/docs/java/datastore/entities#Java_Ancestor_paths
KeyFactory Java doc:
https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/KeyFactory#keyToString(com.google.appengine.api.datastore.Key)
I'm in OPA for some days now and I really start to like it. I'm attending the first year of computer science and we make some database class the next year-
The little I know about Databases are from php, I have used MySQL with php and SQLlite with c++. But this type of database is a bit different from what I've seen.
I have followed the guide about database in OPA http://doc.opalang.org/manual/Hello--database but I have a question:
In the guide we declare a new Database:
type user_status = {regular} or {premium} or {admin}
type user_id = int
type user = { user_id id, string name, int age, user_status status }
database users {
user /all[{id}]
/all[_]/status = { regular }
}
We learn how to read this database and make some query to this database with Maps, but how do I add a new element? I was testing a bit:
/users/all[{id:0}]/name<-getusername;
but id should be auto increment, from the little I know.
Thanks everyone for the help =D
I really want to get in OPA, the little I have make is really impressive!
mongoDB and auto-increment
With mongoDB (the default Opa database) there is no auto-increment (like in SQL), for scalability reason.
But if you really need one, you can use a counter to create this feature yourself:
database users {
user /all[{id}]
int /fresh_key
/all[_]/status = { regular }
}
And increment the key each time you use it: /users/fresh_key++
Random fresh key
You can also generate a random id, for example with something like Random.string(6)
Read this thread to learn more about this technique: http://lists.owasp.org/pipermail/opa/2012-April/001052.html
User defined unique key
But if you are dealing with users, maybe you already have a unique key: what about using "login" or "email" as the unique key?
You can also use Date.in_milliseconds(Date.now_gmt()) for a more unique id, maybe concatenated with the user id
What is the best method to create a database for the given example model and assign each entry with a unique key/name which I already have and to overwrite it if the given key/name shows up again. From what I read you are supposed to use keyname? But I am not getting it to overwrite.
class SR(db.Model):
name = db.StringProperty()
title = db.StringProperty()
url = db.StringProperty()
s = SR(key_name="t5-2rain")
s.name = 't5-2rain'
s.title = 'kaja'
s.url = 'okedoke'
db.put(s)
If I enter this again with the same key name but different title value, will create another entry how do I overwrite an existing value with the same key-name.
Basically how do I populate a table with unique identifiers and overwrite values if the same unique identifier already exist?
I realize I can search for an existing name or key name etc, call that object make the changes to the instances and repopulate but, I would imagine there has to be a better method than that for overwriting especially if I am trying to put a list where some values may be overwrites and some not.
You've got the right idea already.
If 2 SR entities were constructed with the same key_name argument, then they will have the same Key path. Writing one will overwrite any old SR entity which had that key_name argument.
You should be able to observe this by querying the datastore for the entity with its unique key:
s = db.get(db.Key.from_path('SR', 't5-2rain'))