Not sure if this is possible, but it's always worth asking.
I've simplified the problem below - basically, I want to use a for loop to create multiple entities of the same kind. The problem seems to be that I can't name a new entity by calling a variable.
Can anybody think of a way round this problem? Any help would be much appreciated.
Many thanks
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Key roomkey = KeyFactory.createKey("E15", "ids");
String test = "";
for (int x = 0; x < 7; x++) {
test = ("" + Integer.toString(x));
Entity test = new Entity("E15", roomkey);
}
Assuming you are trying to create 7 entities of type E15 with key names "0" through "6"
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
for (Integer n = 0 ; n < 7 ; ++n ) {
Entity entity = new Entity("E15", n.toString());
datastore.put(entity);
}
The last bit is important. Merely creating an instance of Entity doesn't persist it.
You can create an entity by aslo giving it key_name or id:
Entity entry = new Entity("E15", key_name, roomkey);
or,
Entity entry = new Entity("E15", id, roomkey);
and later you can get the entity:
Key key = KeyFactory.createKey(roomkey, "E15", id);
Entity entry = datastore.get(key);
Entity entity = new Entity("YourKindName",String|Long);
Entity entity = new Entity("YourKindName",""+x);//using string as key
//or
Entity entity = new Entity("YourKindName",x);//using number as key
Related
I am trying insert an item in MongoDB using Java MongoDB driver.Before inserting I am trying to get nextId to insert,but not sure why I am always getting nextId as 4 .I am using below given method to get nextId before inserting any item in Mongo.
private Long getNextIdValue(DBCollection dbCollection) {
Long nextSequenceNumber = 1L;
DBObject query = new BasicDBObject();
query.put("id", -1);
DBCursor cursor = dbCollection.find().sort(query).limit(1);
while (cursor.hasNext()) {
DBObject itemDBObj = cursor.next();
nextSequenceNumber = new Long(itemDBObj.get("id").toString()) + 1;
}
return nextSequenceNumber;
}
I have total 13 record in my mongodb collection.What I am doing wrong here?
Please don't do that. You don't need create a bad management id situation as the driver already do this in the best way, just use the right type and annotation for the field:
#Id
#ObjectId
private String id;
Then write a generic method to insert all entites:
public T create(T entity) throws MongoException, IOException {
WriteResult<? extends Object, String> result = jacksonDB.insert(entity);
return (T) result.getSavedObject();
}
This will create a time-based indexed hash for id's which is pretty much more powerful than get the "next id".
https://www.tutorialspoint.com/mongodb/mongodb_objectid.htm
How can you perform Arithmetic operations like +1 to String
nextSequenceNumber = new Long(itemDBObj.get("id").toString()) + 1;
Try to create a Sequence collection like this.
{"id":"MySequence","sequence":1}
Then use Update to increment the id
// Query for sequence collection
Query query = new Query(new Criteria().where("id").is("MySequence"));
//Increment the sequence by 1
Update update = new Update();
update.inc("sequence", 1);
FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
findAndModifyOptions.returnNew(true);
SequenceCollection sequenceCollection = mongoOperations.findAndModify(query, update,findAndModifyOptions, SequenceCollection.class);
return sequenceModel.getSequence();
I found the work around using b.collection.count().I simply find the total count and incremented by 1 to assign id to my object.
I would like to specify. May I receive elements only from DynamoDBIndexHashKey, not use DynamoDBHashKey?
I have a table with fields
#DynamoDBIndexHashKey (attributeName = "count", globalSecondaryIndexName = "count-index")
#DynamoDBHashKey(attributeName="cluster_output_Id)"
#DynamoDBRangeKey(attributeName="last_fetch)"
I have no #DynamoDBIndexRangeKey
It's code:
MyEntity myEntity = new MyEntity();
myEntity.setCount(1); // Integer
DynamoDBQueryExpression<NewsDynamoDb> queryExpression = new DynamoDBQueryExpression<NewsDynamoDb>()
.withHashKeyValues(myEntity)
.withIndexName("count-index");
queryExpression.setConsistentRead(false);
List<MyEntity> myCollection = mapper.query(MyEntity.class, queryExpression);
Error:
AmazonServiceException: Status Code: 400, AWS Service: AmazonDynamoDBv2, AWS Request ID: I97S04LDGO6FSF56OCJ8S3K167VV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Code: ValidationException, AWS Error Message: One or more parameter values were invalid: Invalid number of argument(s) for the EQ ComparisonOperator
How I can get items from DynamoDBIndexHashKey?
P.s. Scan - work but not interesting to me, because in a further I want a sorting
Query with DynamoDBHashKey work. I have problems with DynamoDBIndexHashKey
same example
It is the answer to my question
entity:
#DynamoDBHashKey(attributeName="cluster_output_Id")
public Integer getCluster_output_Id() {
return cluster_output_Id;
}
#DynamoDBIndexHashKey(attributeName = "count", globalSecondaryIndexName = "count-index")
public Integer getCount() {
return count;
}
#DynamoDBRangeKey(attributeName="last_fetch")
#DynamoDBIndexRangeKey(attributeName = "last_fetch", globalSecondaryIndexName = "count-index")
public Date getLast_fetch() {
return last_fetch;
}
code:
dynamoDBMapper = new DynamoDBMapper(amazonDynamoDBClient);
MyClass myClass= new MyClass();
DynamoDBQueryExpression<MyClass > queryExpression = new DynamoDBQueryExpression<MyClass >();
myClass.setCount(1);
queryExpression.setHashKeyValues(myClass);
queryExpression.withIndexName("count-index"); // it's not necessarily
Condition rangeKeyCondition = new Condition();
rangeKeyCondition.withComparisonOperator(ComparisonOperator.NE)
.withAttributeValueList(new AttributeValue().withS(""));
queryExpression.setConsistentRead(false);
List entities = dynamoDBMapper.query(MyClass.class, queryExpression);
Thank you!
like explained here
Table table = dynamoDB.getTable("tableName");
Index index = table.getIndex("count-index");
ItemCollection<QueryOutcome> items = null;
QuerySpec querySpec = new QuerySpec();
querySpec.withKeyConditionExpression("count= :v_count > 0 ")
.withValueMap(new ValueMap() .withString(":v_count","1");
items = index.query(querySpec);
while (iterator.hasNext()) {
//.......
}
You cannot use Query to find items based on sort/range key only.
You can read more here.
In a Query operation, you use the KeyConditionExpression parameter to determine the items to be read from the table or index. You must specify the partition key name and value as an equality condition. You can optionally provide a second condition for the sort key (if present).
In this case your options are:
Scan operation with last_fetch as filter.
Redesign your database to have a GSI with last_fetch as partition key
I just switched to the last version of Morphia (1.0.1). The previous one was com.github.jmkgreen.morphia 1.2.3.
I don't know how to replace LongIdEntity.StoredId. I use it to increment a long id.
edit : Here is how it worked before:
public Key<Snapshot> save(PTSnapshot entity) {
if (entity.getId() == null) {
String collName = ds.getCollection(getClass()).getName();
Query<StoredId> q = ds.find(StoredId.class, "_id", collName);
UpdateOperations<StoredId> uOps = ds.createUpdateOperations(StoredId.class).inc("value");
StoredId newId = ds.findAndModify(q, uOps);
if (newId == null) {
newId = new StoredId(collName);
ds.save(newId);
}
entity.setId(newId.getValue());
}
return super.save(entity);
}
StoredId class is just a POJO with 3 fields:
id
className (to store the type of object the auto-increment will be done on, but you could store something lese, this is just used to retrieve the adequate increment value, because you could have more than one auto-incremented collection !)
value (to store the current value of the auto-increment)
But it is just an helper, you can reproduce the behavior all by yourself.
Basically you just need a collection where you store a simple number, and increment it with findAndModify() each time a new object is inserted.
My thought is that Morphia/Mongo decided to remove this because auto-increments are not recommended with Mongo databases, and ObjectIds are more powerful.
Thanks.
Here is the answer:
if (entity.getId() == null) {
DBCollection ids = getDatastore().getDB().getCollection("ids");
BasicDBObject findQuery = new BasicDBObject("_id", getClass().getSimpleName());
DBObject incQuery = new BasicDBObject("$inc", new BasicDBObject("value", 1));
DBObject result = ids.findAndModify(findQuery, incQuery);
entity.setId(result == null || !result.containsField("value") ? 1L : (Long) result.get("value"));
}
I am using Google App Engine and trying to query / pull data from the Datastores. I have followed nearly 20 different tutorials without any luck.
Here is a picture of my Datastore and the respective sample data I have stored in there:
Here is some of the code I have to pull the data:
//To obtain the keys
final DatastoreService dss=DatastoreServiceFactory.getDatastoreService();
final Query query=new Query("Coupon");
List<Key> keys = new ArrayList<Key>();
//Put the keys into a list for iteration
for (final Entity entity : dss.prepare(query).asIterable(FetchOptions.Builder.withLimit(100000))) {
keys.add(entity.getKey());
}
try {
for (int i = 0; i < keys.size(); i++){
Entity myEntity = new Entity("Coupon", keys.get(i));
System.out.println("Size of the Keys array = " + keys.size());
String description = (String) myEntity.getProperty("desc");
String endDate = (String) myEntity.getProperty("endDate");
System.out.println("Description = " + description);
System.out.println("End Date: " + endDate);
//Map here is empty...
Map<String, Object> test = myEntity.getProperties();
System.out.println("MAP SIZE = " + test.size());
}
} catch (Exception e){
e.printStackTrace();
}
**OUPUT:**
Size of the Keys array = 2
Description = null
End date = null
MAP SIZE = 0
I have no clue why the description and end date are null. It is clearly pulling in the right Entity as the size shows 2, which matches the picture shown. Also, when I print the keys out, it matches as well
(Something like this: for the keys.get(i).toString(); -- Entity [!global:Coupon(123)/Coupon(no-id-yet)]:
. Or: Key String = !global:Coupon(5730827476402176)
I have followed the documentation (here) and some examples (here) to the best of my ability but I cannot seem to figure it out. Does anyone have any recommendations or experience in how to obtain the properties from Entities once you have them without them returning null?
I have gone through the following Stackoverflow questions without any success so please do not close this with a simple duplicate question marker on it:
1) How do i get all child entities in Google App Engine (Low-level API)
2) Storing hierarchical data in Google App Engine Datastore?
3) How do you use list properties in Google App Engine datastore in Java?
4) Mass updates in Google App Engine Datastore
5) Checking if Entity exists in google app engine datastore. .
have you tried this?
//Put the keys into a list for iteration
for (final Entity entity : dss.prepare(query).asIterable (FetchOptions.Builder.withLimit(100000))) {
String description = (String) entity.getProperty("desc");
String endDate = (String) entity.getProperty("endDate");
System.out.println("Description = " + description);
System.out.println("End Date: " + endDate);
}
In your example, you creating entity and it is expected that properties will be empty
Eureka! Many thanks to all that answered. Patrice and user2649908 especially thank you as you led me to the answer.
So, Patrice was entirely correct in that I was querying to get the keys, building a new entity, and then trying to parse the newly created (empty) entity.
The solution was to utilize PersistenceManager to parse the data and then use getter/ accessor methods to do so. The link for persistence manager (which I more or less just copied directly from as it worked perfectly) is here:
How to use JDO persistence manager?
Once I setup the persistence manager, I was able to get it to pull the data using this code:
try {
for (int i = 0; i < keys.size(); i++){
//See the link for How to use JDO persistence manager on how to use this
PersistenceManager pm = MyPersistenceManagerClass.getPM();
//Need to cast it here because it returns an object
Coupon coupon = (Coupon) pm.getObjectById(Coupon.class, keys.get(i));
System.out.println("Created by = " + coupon.getCreatedBy());
System.out.println("Description = " + coupon.getDesc());
System.out.println("Modified by = " + coupon.getModifiedBy());
}
} catch (Exception e){
e.printStackTrace();
}
Following the GAE official doc i try to test it in my local dev environment(unit test), unfortunately the entity group count always return 0:
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
MemcacheService memcacheService = MemcacheServiceFactory.getMemcacheService();
Entity entity1 = new Entity("Simple");
Key key1 = ds.put(entity1);
Key entityGroupKey = Entities.createEntityGroupKey(key1);
//should print 1, but 0
showEntityGroupCount(ds, memcacheService, entityGroupKey);
Entity entity2 = new Entity("Simple", key1);
Key key2 = ds.put(entity2);
//should print 2, but still 0
showEntityGroupCount(ds, memcacheService, entityGroupKey);
below are copied from the doc for quick reference:
// A simple class for tracking consistent entity group counts
class EntityGroupCount implements Serializable {
long version; // Version of the entity group whose count we are tracking
int count;
EntityGroupCount(long version, int count) {
this.version = version;
this.count = count;
}
}
// Display count of entities in an entity group, with consistent caching
void showEntityGroupCount(DatastoreService ds, MemcacheService cache, PrintWriter writer,
Key entityGroupKey) {
EntityGroupCount egCount = (EntityGroupCount) cache.get(entityGroupKey);
if (egCount != null && egCount.version == getEntityGroupVersion(ds, null, entityGroupKey)) {
// Cached value matched current entity group version, use that
writer.println(egCount.count + " entities (cached)");
} else {
// Need to actually count entities. Using a transaction to get a consistent count
// and entity group version.
Transaction tx = ds.beginTransaction();
PreparedQuery pq = ds.prepare(tx, new Query(entityGroupKey));
int count = pq.countEntities(FetchOptions.Builder.withLimit(5000));
cache.put(entityGroupKey,
new EntityGroupCount(getEntityGroupVersion(ds, tx, entityGroupKey), count));
tx.rollback();
writer.println(count + " entities");
}
}
Any ideas about this problem? Thanks in advance.
Entities.createEntityGroupKey() is being called twice as a result of method nesting. Change both occurrences of
showEntityGroupCount(ds, memcacheService, entityGroupKey);
to
showEntityGroupCount(ds, memcacheService, key1);
and the correct counts appear (in the development environment anyway).