How to update array property values in Google Cloud Datastore - java

I am using Datastore in Firestore mode for my Google App Engine app. I know how to store list/array property values in the Google Cloud Datastore. But how do I update these values (ex: add new values to the list?) I could not find an example in the documentation.
This is how you would add a list property to the datastore initially:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity user = new Entity("User");
List<String> items = new ArrayList<String>();
user.setProperty("ItemsList", items);
datastore.put(user);
But what do I do if later on, I want to access an User entity's list of items and add an item to that list?

Thanks for the clarification. Now I understand that you want to be able to just add things to that list instead of overwriting the whole list.
Reading at the documentation for Datastore I can see that you can't just update a property.
To update an existing entity, modify the properties of the entity
previously retrieved and store it using the key
I your case you would do something like retrieve the data of the list, then append the new element or update something in that list and then update the whole list again like:
Entity task = Entity.newBuilder(datastore.get(user)).set("ItemsList", items).build();
datastore.update(user);

Related

How could I insert a new item in a existing node in Firebase?

I would like to know how i could add a new value to a existing child or node in Firebase.
The structure of my Firebase child is like this
and i would like to insert a new value and upload this specific child.
The result i would like to get is the next
As you can see I inserted the key --> "key" and the value "-LEkCo-4bwHd8ThOM27i"
Finally trying to specify more.. the structure of my entire Database is the next
I did it with the Firebase console but i would like to do from my app.
Any thoughts??
Thanks in advance!!
You can use updateChildren():
To simultaneously write to specific children of a node without overwriting other child nodes, use the updateChildren() method.
DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child(randomid);
Map<String, Object> updates = new HashMap<String,Object>();
updates.put("userid", newID);
ref.updateChildren(updates);

How to listen for change in a collection?

I have to check for changes in an old embedded DBF database which is populated by an old third-party application. I don't have access to source code of that application and cannot put trigger or whatever on the database. For business constraint I cannot change that...
My objective is to capture new records, deleted records and modified records from a table (~1500 records) of that database with a Java application for further processes. The database is accessible in my Spring application though JPA/Hibernate with HXTT DBF driver.
I am looking now for a way to efficiently capture changes made by the third-party app in the database.
Do I have to periodically read the whole table and check if each record is still unchanged or to apply any kind of diff within two readings? Is there a kind of "trigger" I can set in my Java app? How to listen properly for those changes?
There is no JPA mechanism for getting callbacks from a database when the data changes.
The only options is to build your own change detection. Typically you would start by detecting which entities were added, removed, and which still exists. For the once that still exist you will need to check if they are changed, so the entity needs an equals() method.
An entity is identified by it primary key, so you will need to get the set of all primary keys, once you have that you can easily use Guava's Sets methods to produce the 3 sets of added, removed, and existing (before and now), like this.
List<MyEntity> old = new ArrayList<>(); // load from the DB last time
List<MyEntity> current = new ArrayList<>(); // loaded from DB now
Map<Long, MyEntity> oldMap = old.stream().collect(Collectors.toMap(MyEntity::getId, Function.<MyEntity>identity() ));
Map<Long, MyEntity> currentMap = current.stream().collect(Collectors.toMap(MyEntity::getId, Function.<MyEntity>identity()));
Set<Long> oldKeys = oldMap.keySet();
Set<Long> currentKeys = currentMap.keySet();
Sets.SetView<Long> deletedKeys = Sets.difference(oldKeys, currentKeys);
Sets.SetView<Long> addedKeys = Sets.difference(currentKeys, oldKeys);
Sets.SetView<Long> couldBeChanged = Sets.intersection(oldKeys, currentKeys);
for (Long id : couldBeChanged) {
if (oldMap.get(id).equals(currentMap.get(id))) {
// entity with this id was changed
}
}

Is it possible to store List<Key> as property of a Entity in Google App Engine (GAE)?

List<Key> items = new ArrayList<Key>();
user.setProperty("ItemsList", items);
The code given above does not work. What are the ways in which this can be achieved using Java platform in GAE ?
P.S. Though the following piece of code runs fine -
List<String> items = new ArrayList<String>();
user.setProperty("ItemsList", items);
It should work without any problems. Did you forget to put the item? If you didn't set id for the item, the DataStore will automatically assign the entity an integer numeric ID. You need to put that generated key into the list.
Here is the sample code:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity item = new Entity("Item");
datastore.put(item);
Entity user = new Entity("User");
List<Key> items = new ArrayList<Key>();
items.add(item.getKey());
user.setProperty("ItemsList", items);
datastore.put(user);
Please check the doc: https://developers.google.com/appengine/docs/java/datastore/entities
And, it is better to handle data layer via some third part API like Objectify: http://code.google.com/p/objectify-appengine/
It should work.
Infact, that's one of the ways used to implement many-to-many and many-to-one relationships.
See, for example, http://code.google.com/p/objectify-appengine/wiki/IntroductionToObjectify#Multi-Value_Relationship
Key used in the Objectify example is com.googlecode.objectify.Key<T> though.
You cannot store an empty collection in the datastore. It must contain at least one value. Could it be that you missed out...
items.add(item.getKey());

how to delete multiple data using check box in google app engine (JAVA)

In Google app engine, how can i delete multiple data selected in check box. For a sample i had attached the image below. here i had selected the multiple check boxes and the data shown are stored in the Google app engine.
i have my jsp code for check box like this,
<input name="delete" type="checkbox"/>
can anyone suggest me how to select the data and delete it from Google app engine.
Edited:
For storing the data i used,
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity employee = new Entity("Employee");
employee.setProperty("First Name", fname);
datastore.put(employee);
For retrieving the data i used,
Query query = new Query("Employee");
List<Entity> emp = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(20));
for (Entity user : emp){
// inside the table
user.getProperty("File Name")}
By this i can retrieve the data.
First of all, I recommend that you use two frameworks to make your life easier:
Stripes
Objectify
OK, here you go: I'm not sure to which degree your question is a basic JSP/Servlet question or a specific Appengine question. However, you have to do the follwoing:
Have a list of checkboxes on your JSP page, like this: <stripes:checkbox name="employees[${loop.index}].id" value="${employee.id}"/> (see: http://www.stripesframework.org/display/stripes/Indexed+Properties)
Pass a list of IDs (of the entities that should be deleted) to the Servlet.
Delete the entities based on these IDs.
Here's the catch: Appengine can terminate the request before all entities are deleted. That can happen if the request takes too long. Therefore you should delete the entities asynchronously, using chunks of data. See this answer for further information.

Amazon DynamoDB to Get Items with attribute value of... (Java API)

I'm fairly new to Amazon's AWS and its API for Java, so I'm not exactly sure what the most efficient method for what I'm trying to do would be. Basically, I'm trying to setup a database that will store a project's ID, it's status, as well as the bucket and location when uploaded to an S3 bucket by a user. What I'm having trouble with is getting a list of all the project IDs that have a status of "ready" under the status attribute. Any projects that are of status "ready" need to have their ID numbers loaded to an array or arraylist for later reference. Any recommendations?
The way to do this is to use the scan API. However, this means dynamo will need to look at every item in your table, and check if its attribute "status" is equal to "ready". The cost of this operation will be large, and will charge you for reading every item in your table.
The code would look something like this:
Condition scanFilterCondition = new Condition()
.withComparisonOperator(ComparisonOperator.EQ.toString())
.withAttributeValueList(new AttributeValue().withS("ready"));
Map<String, Condition> conditions = new HashMap<String, Condition>();
conditions.put("status", scanFilterCondition);
ScanRequest scanRequest = new ScanRequest()
.withTableName("MasterProductTable")
.withScanFilter(conditions);
ScanResult result = client.scan(scanRequest);
There is a way to make this better, though it requires denormalizing your data. Try keeping a second table with a hash key of "status", and a range key of "project ID". This is in addition to your existing table. This would allow you to use the Query API (scan's much cheaper cousin), and ask it for all items with a hash key of "ready". This will get you a list of the project IDs you need, and you can then get them from the project ID table you already have.
The code for this would look something like:
QueryRequest queryRequest = new QueryRequest()
.withTableName("ProductByStatus")
.withHashKeyValue(new AttributeValue().withS("ready"));
QueryResult result = client.query(queryRequest);
The downside to this approach is you have to update two tables whenever you update the status field, and you have to make sure that you keep them in sync. Dynamo doesn't offer transactionality, so you have to be ready for the case where the update to the master project table succeeds, but your secondary status table doesn't. Or vice-versa.
For further reference: http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/QueryAndScan.html

Categories