How to represent the following query(mongodb) in java - java

I have a JSON in MongoDB with the following structure:
{
id:"_234234",
"stationId":"ALM",
"storageData": {
}
}
To retrieve JSON with storageData equal to null, in MongoDB I query as:
db.collection.find({"storageData":{"$gt" : {}}})
It gives me list of JSON bodies with empty storageData. So how do I represent that in Java
BasicDBObject obj=new BasicDDBObject("storageData", new BasicDBObject("$gt",{}));
collection.find(obj);
I am getting an error near BasicDBObject("$gt",{}))...
How do I represent ("$gt",{}) in Java??

First understand that null is a valid value. This would be valid:
{
id:"_234234",
StationId:"ALM",
StorageData: null
}
and retrieving the document, asking for storagedata which is null would retrieve the doc with the id _234234.
If what you need is to check which documents DON'T have the key "storagedata" then use the $exist keyword or construct the query in this way:
db.yourcollection.find("this.storagedata == null")
I would do it via query, and not in Java because it would alleviate cpu time and memory.

All you want to to here is represent an empty object:
BasicDBObject query = new BasicDBObject(
"storageData", new BasicDBObject(
"$gt",new BasicDBObject()
)
);
Which of course produces the query:
{ "storageData" : { "$gt" : { } } }
So that's it, just call BasicDBObject without any arguments.

Related

Remove document from array in MongoDB Java

I got a JSON string that looks something like this:
String tmp = "[
{
"ID":"12",
"Date":"2018-02-02",
"ObjData":[
{
"Name":"AAA",
"Order":"12345",
"Extra1":{
"Temp":"3"
},
"Extra2":{
"Temp":"5"
}
},
{
"Name":"BBB",
"Order":"54321",
"Extra1":{
"Temp":"3"
},
"Extra2":{
"Temp":"5"
}
}
]
}
]"
I would like to remove for example the the document where ´Order´ equals "54321" from ´ObjData´. I got the following code:
Document doc = new Document();
doc = Document.parse(tmp);
Document fields = new Document("ID", "12")
.append("ObjData", Arrays.asList(new Document("Order", "54321")));
Document update = new Document("$pull", fields);
coll.updateOne(doc, update);
I am trying to use the ´pull´ method to remove the entire document from the array where the ´Order´ equals 54321 but for some reason it's not working, I am probably doing something wrong. Could someone point out the issue please?
Also, what would be the best way to keep count of the documents within the array so that once all documents are pulled the entire document is deleted from the database? Would it be good to add some kind of ´size´ attribute and keep track of the size and decrease it after each pull?
To remove document with Order=54321 from internal array from any document (if you don't know ID) you can use empty filter like:
Document filter = new Document();
Document update = new Document("$pull", new Document("ObjData", new Document("Order", "54321")));
coll.updateOne(filter, update);
Updating records to remove values from ObjData array
The first parameter to the updateOne method is a query to find the document you want to update, not the full document.
So for your code, assuming ID is a unique value and that there's an item in your collection with an ID of "12":
// { ID: "12" }
Document query = new Document("ID", "12");
// { ObjData: { $pull: { Order: "54321" } } }
Document update = new Document("ObjData",
new Document("$pull",
new Document("Order", "54321")
)
);
coll.updateOne(query, update);
Alternatively, if you want to remove the order from all documents in the database, just replace query with an empty Document, i.e.:
// { <empty> }
Document query = new Document();
Deleting records with empty ObjData array
As for removing records when the size reaches zero, you can use a filter with $size:
db.myColl.deleteMany({ ObjData: { $size: 0 } })
This is also doable using the Java driver:
// { ObjData: { $size: 0 } }
Document query = new Document("ObjData",
new Document("$size", 0)
);
coll.deleteMany(query);
Note that for large collections (i.e. where myColl is large, not the ObjData array), this may not perform very well. If this is the case, then you may want to track the size separately (as you hinted at in your question) and index it to make it faster to search on since you can't create an index on array size in MongoDB.
References
updateOne documentation for updating documents using the Java driver
deleteOne documentation for deleting documents using the Java driver
$pull documentation for removing documents from an array
$size documentation for filtering documents based on the size of an array

Hibernate OGM result of aggregation query

I am using hibernate ogm 5.1 in my application and I construct this query. This query
String query = "db.SWMessages.aggregate( [ {0}, {1} ] )";
Document q1 = new Document("$match",new Document("messageUuid",new
Document("$ne" , id.toString())));
Document q2 = new Document("$group", new Document("_id",
"$localReference").append("max", new Document("$max","$creationDate")));
Object[] param = { q1.toJson(), q2.toJson() };
String nativeQuery = MessageFormat.format(query, param);
List<SWMessageR> records = (List<SWMessageR>) em.createNativeQuery(nativeQuery, SWMessageImpl.class)
.getResultList();
the above code produces the query like this:
db.SWMessages.aggregate([ { "$match" : { "messageUuid" : { "$ne" : "9c1464d7-311d-4b50-8b81-005bad055232" } } } , { "$group" : { "_id" : "$localReference", "max" : { "$max" : "$creationDate" } } } ])
My question is that the result of this query would return back an entity object which is the SWMessageR?
Well, yes the way you execute your query it will return a List Object of your class. In this way you don't need to use casting, so you can use it like this:
List<SWMessageR> records = em.createNativeQuery(nativeQuery, SWMessageImpl.class).getResultList();
Though, in case you are expecting a single result, I would suggest to use this way:
SWMessageR record = (SWMessageR) em.createNativeQuery( query1, SWMessageR.class ).getSingleResult();
Have a look at the Hibernate Search Documentation Query Section and everything will be clear.
Cheers.
Hibernate OGM can convert the result into an entity: https://docs.jboss.org/hibernate/stable/ogm/reference/en-US/html_single/#ogm-mongodb-queries-native
I'm not sure what your query returns, but if it's a document in the collection that represents your entity, I expect it to work.
You can see an example in our code base:
https://github.com/hibernate/hibernate-ogm/blob/master/mongodb/src/test/java/org/hibernate/ogm/datastore/mongodb/test/query/nativequery/MongoDBSessionCLIQueryTest.java#L111
Make sure to pass the expected Entity type, it will look something like this:
List<SWMessageR> results = em
.createNativeQuery( nativeQuery, SWMessageR.class )
.getResultList();
Assuming that SWMessageR is the entity class.

How to set value in nested BasicDBObject with Java MongoDB driver

I have a mongo document that I am trying to update before insert in mongodb.
I have to put theses 3 keys
document._parentId = ObjectId()
document.aDictionnary.actionId = Integer
document.aDictionnary.bDictionnary.id = Integer
I have tried a few combinaison, but can't make it work.
Here is my current code
myClass.getDocument().append( "$set", new BasicDBObject().append("_parentId", myClass.getDocument.getId() ) );
myClass.getDocument().append( "$set", new BasicDBObject().append("aDictionnary", new BasicDBObject().append("actionId", actionToAttachId ) ) );
if( null == myClass.getSiteId() )
{
myClass.getDocument().append( "$set", new BasicDBObject().append("aDictionnary", new BasicDBObject().append("bDictionnary", new BasicDBObject().append( "id", actionToAttach.getSiteId() ))));
}
I don't want to directly update my document in database, reason is I keep all the history so each entry is a new insert.
Application doesn't crash, but fail on insert because of a wrong "append" syntax
Also I think it's unpleasing to write that kind of code because of the nested basicdbobject.append syntax, is there another way to do so ?
Here is the stack trace
163530 [http-8080-8] ERROR com.myapp.persistance.mystuff.MyClassMongo - java.lang.IllegalArgumentException: fields stored in the db can't start with '$' (Bad Key: '$set')
Have you tried the $push operator?
Example:
db.students.update({ _id: 1 },{ $push: { scores: 89 }})
In your example:
document._parentId = ObjectId()
document.aDictionnary.actionId = Integer
document.aDictionnary.bDictionnary.id = Integer
Essentially that equates to:
{_parentId: ObjectId(), aDictionary: {actionId: actionId,
bDictionnary: {id: id}}
So there are 3 documents - the toplevel all the way down to the nested bDictionnary. Each one of these is a DBObject so you'd need to build up the DBObject and save it as appropriate - here is some untested pseudo code:
DBObject myDocument = new BasicDBObject();
myDocument.put("_parentId", ObjectId())
DBObject aDictionary = new BasicDBObject("actionId", actionId)
.append("bDictionary", new BasicDBObject("id", id))
myDocument.put("aDictionary", aDictionary)
db.save(myDocument)

Define and Retrieve key-values in MongoDB

I want to define a document in MongoDB in order to keep a list of key-value pairs in addition to some more information . I need to query on keys and extract just values , not whole the document. Let’s say it looks like:
{ title :” Do not stop me now”
Artist: “Queen”
Info :{
Metadata: [
{key: “genre”, value: “Rock” },
{key: “bps”, value: 120}
]
}
}
I selected this format based on http://java.dzone.com/articles/indexing-schemaless-documents
I want to query like select “genre” from song where artist is “Queen”
My current code is:
BasicDBObject eleMatch = new BasicDBObject();
eleMatch.put("key","genre");
BasicDBObject up = new BasicDBObject();
up.put("$elemMatch",eleMatch);
BasicDBObject query = new BasicDBObject();
query.put("info.Metadata", up);
query.put(“Artist”,”Queen”);
BasicDBObject fields = new BasicDBObject("info.Metadata.$",1).append("_id", false);
DBObject object =collection.findOne(query,fields);
I tried to extract value like:
System.out.println( (((BasicBSONList) ((BasicBSONObject) object.get("info")).get("Metadata")).get("value")).toString());
But I cannot get access to "value"
How I can solve it?
The positional operator return an array of one element. So, what you are converting to string is an array and of course you will get a kind of java id.
Cast it to array and get its first element

CSV to GeoJSON conversion

I want to convert a CSV line into a GeoJSON object. I am using CSVReader. Hence, nextLine[] has all the separated tokens.
I want to create BasicDBObject which has various attributes stored. I am doing it following way.
new BasicDBObject("attribute1",nextLine[0]).append("attribute2",nextLine[1])
What I want to achieve is having a document like this in MongoDB
{
attribute1: name
attribute2: address
location:{ type : "Point" ,
coordinates : [lat, long]
}
attrribute3: phonenumber
}
How do I do this using BasicDBObject?enter code here
The easiest way to do that is using the BasicDBObjectBuilder, an utility class to build DBObjects. You can do something like that:
BasicDBObject toInsert = BasicDBObjectBuilder.start()
.add("attribute1",nextLine[0])
.add("attribute2",nextLine[1])
.add(" attrribute3",nextLine[2])
.push("location")
.add("type", "Point")
.add("coordinates", new double[] { nextLine[3], nextLine[4] })
.pop()
.get()
I did it the other way
double latLong[] = new double[]{10.0, 30.0};
BasicDBObject doc = new BasicDBObject("attr1",nextLine[0])
.append("attr2", nextLine[1]
.append("location",new BasicDBObject("type","Point")
.append("coordinates",latLong))
.append("attr3", nextLine[3])
This also works as desired

Categories

Resources