Get DB object from JDO/DataNucleus and MongoDB with a String _id - java

I am using JDO and DataNucleus to persist runtime-generated objects into MongoDB. The database objects have their own unique identifier, a string, which I put into Mongo's _id field. This works fine and I end up with, for instance, this object:
(in the mongo shell)
> db.CollectionName.find({"_id":"01e293bc-970d-e0b3-aac1-14109fdb7235_ZMUkU234ufY3opYPeov38T4EilNLURIb8ki"}).pretty()
{
"_id" : "01e293bc-970d-e0b3-aac1-14109fdb7235_ZMUkU234ufY3opYPeov38T4EilNLURIb8ki",
...
When I want to get an object back out of Mongo I make the call which I think should work:
PersistenceManager pm = pmf.getPersistenceManager();
String keyString = "01e293bc-970d-e0b3-aac1-14109fdb7235_ZMUkU234ufY3opYPeov38T4EilNLURIb8ki";
Object dbObject = pm.getObjectById(keyString);
But I don't get a dbObject, instead JDO throws a JDONotFoundException. I thought perhaps I needed to specify the class of the DB object which is tough because it is runtime generated, but I added a hack which saves a pointer to the class when I persist, so that I can use it later:
this.savedDBclass = obj.getClass();
pm.makePersistent(obj);
...
PersistenceManager pm = pmf.getPersistenceManager();
String keyString = "01e293bc-970d-e0b3-aac1-14109fdb7235_ZMUkU234ufY3opYPeov38T4EilNLURIb8ki";
Object dbObject = pm.getObjectById(this.savedDBclass, keyString);
and in that case I get a JDOFatalUserException "No metadata has been registered for class".
When I look at the documentation it seems like this procedure should be straightforward: "You can then go back to your data layer and retrieve the object as follows: Object obj = pm.getObjectById(id);"
I figure my problem is that I'm using a String instead of an ObjectId but I can't figure out the voodoo to make String IDs work. I read in the documentation "A DataNucleus extension is to pass in a String form of the identity to the above method" but we aren't using that extension, to the best of my knowledge.

Suggest you read the JDO spec which is very clear what is an "identity" (a String is not it), and what is a PK value. You don't post the class itself, so people are left to guesswork. To get an "identity" you can easily enough do
Object identity = pm.newObjectIdInstance(MyObject.class, "my_pk_value_when_string");
and that is what goes into pm.getObjectById(id). You then look at the log if having problems.

Related

How to pass a dynamically generated list of property names and values in Neo4j for java?

I'm using the Neo4j driver for java which lets you run a query with parameters. I have a dynamically generated list of strings which act as queries,
with each query having different parameters. Examples of query strings include:
"CREATE (a:Person {id:{id}, name:{name}})"
"CREATE (a:Person {id:{id}, name:{name}}, age:{age}})"
"CREATE (a:Person {id:{id}, age:{age}})"
For each of these queries I would need to pass different parameters with the appropriate values in order for node insertion to work properly.
Code snippet for what I'm trying to do is given below:
try (Transaction tx = session.beginTransaction()) {
String queryStr = "CREATE (a:Person {id:{id}, name:{name}})";
tx.run(query, Values.parameters("id", "testId", "name", "testName"));
}
This piece of code works for non-dynamically generated key-value pairs of properties. For the purpose of this example, I've hardcored the value of
the query string (normally, the transaction would run in a loop and each query string would be read from a list). Now, when attempting to pass
parameters, I can only do so using the syntax above.
For example, the syntax:
try (Transaction tx = session.beginTransaction()) {
String queryStr = "CREATE (a:Person {id:{id}, name:{name}})";
Map<String, String> parameterKeyValueMap = new HashMap<String, String>();
parameterKeyValueMap.put("id", "id");
parameterKeyValueMap.put("name", "testName");
tx.run(query, Values.parameters(parameterKeyValueMap));
tx.success();
}
doesn't work, since the Parameters function requires an even number of arguments. Now, I'm not sure how to actually proceed. Obviously, the
Map object itself would also be dynamically generated (I've just used a simplified example).
Any help/tips would be greatly appreciated!
You want to pass in the Map parameter directly into the run method (as the second parameter), instead of relying on Neo4j's Values interface. There is no need for casting of the Map object into the Values object.
I don’t know Neo4j but CREATE uses executeUpdate in JDBC rather than executeQuery as this is a dB write operation. Query is a dB read operation.

Get the object id after inserting the mongodb document in java

I am using mongodb 3.4 and I want to get the last inserted document id. I have searched all and I found out below code can be used if I used a BasicDBObject.
BasicDBObject docs = new BasicDBObject(doc);
collection.insertOne(docs);
ID = (ObjectId)doc.get( "_id" );
But the problem is am using Document type not BasicDBObject so I tried to get it as like this, doc.getObjectId();. But it asks a parameter which I actually I want, So does anyone know how to get it?
EDIT
This is the I am inserting it to mongo db.
Document doc = new Document("jarFileName", jarDataObj.getJarFileName())
.append("directory", jarDataObj.getPathData())
.append("version", jarDataObj.getVersion())
.append("artifactID", jarDataObj.getArtifactId())
.append("groupID", jarDataObj.getGroupId());
If I use doc.toJson() it shows me whole document. is there a way to extract only _id?
This gives me only the value i want it like the objectkey, So I can use it as reference key.
collection.insertOne(doc);
jarID = doc.get( "_id" );
System.out.println(jarID); //59a4db1a6812d7430c3ef2a5
Based on ObjectId Javadoc, you can simply instantiate an ObjectId from a 24 byte Hex string, which is what 59a4db1a6812d7430c3ef2a5 is if you use UTF-8 encoding. Why don't you just do new ObjectId("59a4db1a6812d7430c3ef2a5"), or new ObjectId("59a4db1a6812d7430c3ef2a5".getBytes(StandardCharsets.UTF_8))? Although, I'd say that exposing ObjectId outside the layer that integrates with Mongo is a design flaw.

Cannot get _id of MongoDB object with java driver

I'm inserting objects into MongoDB without specifying the _ids, because I want it to create them automatically. The problem is that at a certain point of the program I need to retrieve the _ids, but I can't get them. The code I use is the following:
List<DBObject> objs=collection.find(filter).toArray();
BDObject obj=objs.get(0);
String id=obj.get("_id");
//now id is something like 2d938830-2732-44fd-84b0-aa56b95c5df0
Eventually the id variable contains a GUID, but it's different from the one I see in RoboMongo, so it's wrong. What I see in RoboMongo is something like:
"_id": LUUID("cada0d4f-a72d-47ad-8ea8-239c3e5795dd")

Concurrency - Getting the MongoDB generated ID of an object inserted via Java in a thread safe way

What is the best method to get the Mongo generated ID of a document inserted via Java.
The Java process inserting the documents is multi-thread, meaning that we need some atomic way to insert and return the ID of the object.
Also, if we setup a unique index, in the event that the object is a duplicate, will an ID be returned?
Thanks!
Generate the ObjectId early, use it in the insert, and there will no need to have the database return it to you.
ObjectId doesn't use a shared sequence number to be unique, so it doesn't matter if you generate one before inserting or retrieve it after.
public ObjectId createThing() {
ObjectId result = new ObjectId();
BasicDBObject thingToInsert = new BasicDbObject();
thingToInsert.put('_id', result);
//set other fields here
collection.insert(thingToInsert);
return result;
}
native ObjectId's which are generated by Mongo are globally unique and can be safely used from the multi-threaded application.
generated ObjectId can be obtained from the DbObject under _id key.
If inserted document violates a unique index constraint - java driver may throw an exception, depending on a value of WriteConcern:
http://api.mongodb.org/java/current/com/mongodb/WriteConcern.html
If it's value is higher then NORMAL- exception will be thrown.
WriteConcern can be specified for every individual insert (or update) method, or globally by using DBCollection.setWriteConcern
I retrieve the document with _id but when I get the data into my java class eg mobile, _id attribute which is of type ObjectID me I change it set the value of the document in mongodb.

What is wrong with this GeoTools FeatureId?

Using the GeoTools WFS-T plugin, I have created a new row, and after a commit, I have a FeatureId whos .getId() returns an ugly string that looks something like this:
newmy_database:my_table.9223372036854775807
Aside from the fact that the word "new" at the beginning of "my_database" is a surprise, the number in no way reflects the primary key of the new row (which in this case is "23"). Fair enough, I thought this may be some internal numbering system. However, now I want a foreign key in another table to get the primary key of the new row in this one, and I'm not sure how to get the value from this FID. Some places suggest that you can use an FID in a query like this:
Filter filter = filterFactory.id(Collections.singleton(fid));
Query query = new Query(tableName, filter);
SimpleFeatureCollection features = simpleFeatureSource.getFeatures(query);
But this fails at parsing the FID, at the underscore of all places! That underscore was there when the row was created (I had to pass "my_database:my_table" as the table to add the row to).
I'm sure that either there is something wrong with the id, or I'm using it incorrectly somehow. Can anyone shed any light?
It appears as if a couple things are going wrong - and perhaps a bug report is needed.
The FeatureId with "new" at the beginning is a temporary id; that should be replaced with the real result once commit has been called.
There are a number of way to be aware of this:
1) You can listen for a BatchFeatureEvent; this offers the information on "temp id" -> "wfs id"
2) Internally this information is parsed from the Transaction Result returned from your WFS. The result is saved in the WFSTransactionState for you to access. This was before BatchFeatureEvent was invented.
Transaction transaction = new transaction("insert");
try {
SimpleFeatureStore featureStore =
(SimpleFeatureStore) wfs.getFeatureSource( typeName );
featureStore.setTransaction( transaction );
featureStore.addFeatures( DataUtilities.collection( feature ) );
transaction.commit();
// get the final feature id
WFSTransactionState wfsts = (WFSTransactionState) transaction.getState(wfs);
// In this example there is only one fid. Get it.
String result = wfsts.getFids( typeName )[0];
}
finally {
transaction.close();
}
I have updated the documentation with the above example:
http://docs.geotools.org/latest/userguide/library/data/wfs.html

Categories