Objectify NotFoundException - objectify

Why do these 2 fetches result in a NotFoundException?
ofy().load().type(MyClass.class).id(myClassInstance.getId()).safeGet();
ofy().load().key(myClassInstance.getKey()).safeGet();
But this query returns an entity:
ofy().load().type(MyClass.class).filter("fieldName",myClassInstance.getUserId()).first().get();
Additional info:
MyClass contains a #Parent and #Id field

You aren't specifying the parent key when loading by key.
ofy().load().type(MyClass.class).id(myClassInstance.getId()).safeGet();
// should be:
ofy().load().type(MyClass.class).parent(myClassInstance.getParent()).id(myClassInstance.getId()).safeGet();
For the second line, I suspect your implementation of getKey() is flawed and missing the parent key. The query works because the query is not a key lookup; it just returns whatever is in the index for the property.
Remember that ids are only unique for a particular parent. The unique identifier for an entity is {parent, id}. Read https://code.google.com/p/objectify-appengine/wiki/Concepts carefully.

Related

Global Secondary Index DynamoDB empty value error

I have a string attribute that can be an empty value. And I want to set it as a Global Secondary Index. But it showed an error when I tried to perform UpdateItemRequest or SaveTable Context:
Amazon.DynamoDBv2.AmazonDynamoDBException: One or more parameter values are not valid. A value specified for a secondary index key is not supported. The AttributeValue for a key attribute cannot contain an empty string value. IndexName: .... IndexKey: ...
What is wrong with my mindset or my settings? I'm new to DynamoDB and had a MongoDB base. If I don't use GSI for this attribute, how to perform a query on that attribute?
I tried
[DynamoDBIgnore] string property;
var operationConfig = new DynamoDBOperationConfig() { };
operationConfig.IsEmptyStringValueEnabled = true;
operationConfig.Conversion = DynamoDBEntryConversion.V2;
but it does not work.
This states that you are setting the value for your GSI PK to an empty string "" which is not supported.
In order to overcome this, you simply remove any value from that attribute, i.e don't set it at all. This allows your index to become sparse in that it will only store data that has a key associated with it.

DynamoDb - .NET Object Persistence Model - LoadAsync does not apply ScanCondition

I am fairly new in this realm and any help is appreciated
I have a table in Dynamodb database named Tenant as below:
"TenantId" is the hash primary key and I have no other keys. And I have a field named "IsDeleted" which is boolean
Table Structure
I am trying to run a query to get the record with specified "TenantId" while it is not deleted ("IsDeleted == 0")
I can get a correct result by running the following code: (returns 0 item)
var filter = new QueryFilter("TenantId", QueryOperator.Equal, "2235ed82-41ec-42b2-bd1c-d94fba2cf9cc");
filter.AddCondition("IsDeleted", QueryOperator.Equal, 0);
var dbTenant = await
_genericRepository.FromQueryAsync(new QueryOperationConfig
{
Filter = filter
}).GetRemainingAsync();
But no luck when I try to get it with following code snippet (It returns the item which is also deleted) (returns 1 item)
var queryFilter = new List<ScanCondition>();
var scanCondition = new ScanCondition("IsDeleted", ScanOperator.Equal, new object[]{0});
queryFilter.Add(scanCondition);
var dbTenant2 = await
_genericRepository.LoadAsync("2235ed82-41ec-42b2-bd1c-d94fba2cf9cc", new DynamoDBOperationConfig
{
QueryFilter = queryFilter,
ConditionalOperator = ConditionalOperatorValues.And
});
Any Idea why ScanCondition has no effect?
Later I also tried this: (throw exception)
var dbTenant2 = await
_genericRepository.QueryAsync("2235ed82-41ec-42b2-bd1c-d94fba2cf9cc", new DynamoDBOperationConfig()
{
QueryFilter = new List<ScanCondition>()
{
new ScanCondition("IsDeleted", ScanOperator.Equal, 0)
}
}).GetRemainingAsync();
It throws with: "Message": "Must have one range key or a GSI index defined for the table Tenants"
Why does it complain about Range key or Index? I'm calling
public AsyncSearch<T> QueryAsync<T>(object hashKeyValue, DynamoDBOperationConfig operationConfig = null);
You simply cant query a table only giving a single primary key (only hash key). Because there is one and only one item for that primary key. The result of the Query would be that still that single item, which is actually Load operation not Query. You can only query if you have composite primary key in this case (Hash (TenantID) and Range Key) or GSI (which doesn't impose key uniqueness therefore accepts duplicate keys on index).
The second code attempts to filter the Load. DynamoDBOperationConfig's QueryFilter has a description ...
// Summary:
// Query filter for the Query operation operation. Evaluates the query results and
// returns only the matching values. If you specify more than one condition, then
// by default all of the conditions must evaluate to true. To match only some conditions,
// set ConditionalOperator to Or. Note: Conditions must be against non-key properties.
So works only with Query operations
Edit: So after reading your comments on this...
I dont think there conditional expressions are for read operations. AWS documents indicates they are for put or update operations. However, not being entirely sure on this since I never needed to do a conditional Load. There is no such thing like CheckIfExists functionality as well in general. You have to read the item and see if it exists. Conditional load will still consume read throughput so your only advantage would be only NOT retrieving it in other words saving the bandwith (which is very negligible for single item).
My suggestion is read it and filter it in your application layer. Dont query for it. However what you can also do is if you very need it you can use TenantId as hashkey and isDeleted for range key. If you do so, you always have to query when you wanna get a tenant. With the query you can set rangeKey(isDeleted) to 0 or 1. This isnt how I would do it. As I said, would just read it and filter it at my application.
Another suggestion thing could be setting a GSI on isDeleted field and writing null when it is 0. This way you can only see that attribute in your table when its only 1. GSI on such attribute is called sparse index. Later if you need to get all the tenants that are deleted (isDeleted=1) you can simply scan that entire index without conditions. When you are writing null when its 0 dynamoDB wont put it in the index at the first place.

NOT NULL constraint in DynamoDB

I want to use DynamoDB for creating tables. We don't have to specify all the column names while creating schema in DyamoDB and only the primary key(hash key + sort key[optional]). Now if my table does have some other attributes that I want to be there for every item inserted-i.e., add NOT NULL constraint to an attribute other than the key, then how can I achieve it in DynamoDB?
There is no NotNull constraint explicitly available on DynamoDB. However there is a feature to provide default value for the attribute if you are using DynamoDBMapper.
Also, DynamoDB API doesn't allow to add an attribute with empty value (i.e. Null or empty string ''). The API does throw an exception.
In other words, you don't need to define a constraint like RDBMS database. Also, there is no workaround to override this functionality. This condition applies to all attributes i.e you can't have any attributes with NULL or empty value.
Example to set default value using annotation :-
#DynamoDBAutoGeneratedDefault("default")
#DynamoDBAttribute(attributeName = "name")
public String getName() {
return name;
}
com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException:
Supplied AttributeValue is empty, must contain exactly one of the
supported datatypes (Service: AmazonDynamoDBv2; Status Code: 400;
Error Code: ValidationException; Request ID:
1dd8288c-7151-43d3-83d0-dbb7842d705a)

How to access the single child from equalTo(unique) query, without forEach

I need to access the resulting object (key:value) from a query. Here is my query:
root_ref.child('List_Groups').orderByValue().equalTo(group_name).once('value')
.then(function(snapshot){...
The data I'm querying is in this form:
List_Groups
uniqueKey: value,
uniquekey: value,
...
The purpose of the query is to find the unique key associated with the equalTo parameter (group_name). I intended to use orderByValue().equalTo() to grab the single result since group_nameis unique. However, the snapshot it returns is of the form:
List_Groups
uniqueKey: group_name
So snapshot.key returns List_Groups and snapshot.val() returns [object Object]. The key in [object Object] is what I need to access.
I have used forEach to obtain the key, but forEach seems unnecessary to use for this task. Is there another way?
snapshot.child().key would be ideal, however this will obviously not work since child() requires a child path as a parameter. Also, since I am looking for the key, I do not know the key and thus cannot just snapshot.val()[key].
edit:
This is the result of console.log(JSON.stringify(snapshot.val())):
{"-KNgrFphjMX0vlMG2l7G":"newgroup"}
Use this:
var theKey = Object.keys(snapshot.val())[0];
Object.keys() returns an array of all the keys in the object and in your case there will only ever be one key, so [0] will get the first (and only).
CodePen: http://codepen.io/theblindprophet/pen/GqGQaJ

Is it possible to run an ' HAS ANCESTOR' filter/query on a property that contains a list(Value) of keys

I have a kind client that consists of entities with a property psets containing a list of Key
Using the JSON api psets this would expressed as :
psets = { listValue: [ {keyValue: { path: [...]} },{keyValue: { path: [...]} },... ]}
The KeyValues are made of path = [{ kind: 'project', name: 'projectn' }]
I am trying to run an 'ancestor' query on 'client' using
SELECT * from client where psets HAS ANCESTOR KEY( project, 'project1')
This query returns an error: unsupported property
What is unsupported ?
How can I run an 'HAS ANCESTOR' filter on a list of Keys ?
Please note that according the the DataStore Documentation (Operators and comparisons)
A condition can also test whether one entity has another entity as an ancestor, using the HAS ANCESTOR or HAS DESCENDANT operators. These operators test ancestor relationships between keys. They can operate on __key__, but they can also operate on a key-valued property. For HAS ANCESTOR, the right operand cannot be a property
(emphasis mine)
Datastore only supports the HAS ANCESTOR operator on entity keys (i.e. the special __key__ property), not on regular key values.
A possible workaround would be to explicitly include each of the ancestors as a property in the entity.
So for example, if your psets property contained a key project:project1/foo:2/bar:3, you could maintain a separate psets_ancestors list property that contained project:project1, project:project1/foo:2, and project:project1/foo:2/bar:3. Then you could do equality queries on the psets_ancestors property:
SELECT * FROM client WHERE psets_ancestors = KEY(project, 'project1')
(This comes at the cost of extra index entries and having to maintain the separate list property.)

Resources