I wrote query in MongoDB which retrieved two columns, one for id and the other is array. I have tried to read the array using Java but I cannot.
try {
Bson filter = eq("_id", "1260718680159199238");
Bson project = eq("Tweets.Text", 1L);
MongoClient mongoClient = new MongoClient(
new MongoClientURI(
"mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass%20Isolated%20Edition&ssl=false"
)
);
MongoDatabase database = mongoClient.getDatabase("Amazon-tweets");
MongoCollection<Document> collection = database.getCollection("tweets");
FindIterable<Document> result = collection.find(filter).projection(project);
for (Document doc : result) {
String s = doc.getString("Tweets.1");
System.out.println("orig " + s);
}
}//END try
catch (Exception e) {
}//
You can't use the dot notation to retrieve values like that post query.
Depending on the driver version you're using you can use either of these solutions:
(I'm assuming each tweet is a separate document here, but same should apply if it's something different)
List<Document> tweets = (List<Document>) doc.get("Tweets");
List<Document> tweets = doc.getList("Tweets", Document.class); // since 3.10
tweets.forEach(...
You can find the documentation here: https://mongodb.github.io/mongo-java-driver/
Related
My Collection in MongoDB somewhat looks like
_id | Name | Contact
101 | Justin |9999999999
and I am trying to get these values in a String in such a way that is should be like
101Justin9999999999
in my java program but instead, all I can get is
[Document{{_id=101.0, Name=Justin, Contact=9999999999}}]
The code that I have tried so far is as follows :
public static void main( String args[] ) {
MongoClient mongo = new MongoClient( "localhost" , 27017 );
MongoDatabase database = mongo.getDatabase("assingment");
MongoCollection<Document> collection = database.getCollection("mongoData");
FindIterable<Document> iterDoc = collection.find();
String temp="";
Iterator it = iterDoc.iterator();
while (it.hasNext()) {
mongoArrayList.add(it.next().toString());
}
System.out.println(mongoArrayList);
That is correct. When fetching data from your mongo database you'll get a collection of Document objects. You have to provide logic where you . iterate to the collection and build the desired string yourself, based on the field values.
Within each document you can do something like: document.getString("Name"), where Name is one of your column names in your mongo db.
Example code:
while(it.hasNext()) {
Document nextDocument = (Document) it.next();
StringBuilder builder = new StringBuilder();
builder.append(nextDocument.getString("_id")).append(nextDocument.getString("Name")).append(nextDocument.getString("Contact"));
mongoArrayList.add(builder.toString());
}
How could I update a specific field in subdocument of array element ?
My question is similar to the following below, but in my case I need to update just a subdocument value.
MongoDB: How do I update a single subelement in an array, referenced by the index within the array?
I have the following documento model :
{
_id : "xpto",
other_stuff ... ,
templates : [
{
templateId:"template-a"
body: {
en_US:"<p>Hello World!</p>"
}
},
{
templateId:"template-b"
body: {
es_ES:"<p>Holla !</p>"
}
}
]
}
So, In mongodb shell the following statement works perfectly for me:
db.apiClient.update({"_id":"xpto","templates.templateId":"template-b"}, {$set:{"templates.$.body.es_ES":"<h1>Gracias !</h1>"}})
However , when i try to do it with Mongo Java Driver , I get an IllegalArgumentException.
BasicDBObject selectQuery = new BasicDBObject("_id", "xpto");
selectQuery.put("templates.templateId", "template-b");
BasicDBObject updateQuery = new BasicDBObject();
for(String locale : template.getBody().keySet()) {
String updateBodyLocaleExpression = new StringBuilder()
.append("templates.$.body.").append(locale).toString();
String updateBodyLocaleValue = template.getBody().get(locale);
updateQuery.put(updateBodyLocaleExpression, updateBodyLocaleValue);
}
updateQuery.put("$set", updateQuery);
getCollection(COLLECTION_NAME).update(selectQuery, updateQuery, true, true);
It throws the following exception :
Caused by: java.lang.IllegalArgumentException: Invalid BSON field name templates.$.body.es_ES
at org.bson.AbstractBsonWriter.writeName(AbstractBsonWriter.java:494)
at com.mongodb.DBObjectCodec.encode(DBObjectCodec.java:127)
at com.mongodb.DBObjectCodec.encode(DBObjectCodec.java:61)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
at com.mongodb.connection.RequestMessage.addDocument(RequestMessage.java:253)
at com.mongodb.connection.RequestMessage.addCollectibleDocument(RequestMessage.java:219)
at com.mongodb.connection.UpdateMessage.encodeMessageBodyWithMetadata(UpdateMessage.java:77)
at com.mongodb.connection.RequestMessage.encodeWithMetadata(RequestMessage.java:160)
at com.mongodb.connection.WriteProtocol.execute(WriteProtocol.java:85)
Is something wrong with my code ?
Thanks.
Yes. You construct wrong updateQuery. You put fields templates.$.body... in the BasicDbObject and then add same document into $set field into itself. MongoDB tries to update field templates.$.body. and here $ is the part of the field name instead of operator.
Here is working example:
//List is for testing purposes only
List<String> locales = Arrays.asList("en_US", "en_UK");
Document query = new Document("_id", "xpto")
.append("templates.templateId", "template-b");
Document updateQuery = new Document();
for (String locale : locales) {
updateQuery.put("templates.$.body." + locale, "<pre>Updated " + locale + "</pre>");
}
collection.updateOne(query, new Document("$set", updateQuery));
Document is almost the same as BasicDbObject but more general.
I am inserting some value into mongodb in this way.
MongoClient mongo = new MongoClient( "localhost" , 27017 );
DB db = mongo.getDB("test");
DBCollection table = db.getCollection("paramDescMapper");
String key = UUID.randomUUID().toString();
String value = "{\"param0\":\"Car Make\",\"param1\":\"Car Model\",\"param2\":\"Car Variant\",\"param3\":\"Car Year\",\"param4\":\"Car Number\"}";
JSONObject jsonObject = new JSONObject(value);
// create a document to store key and value
BasicDBObject document = new BasicDBObject();
document.put("apiKey", key);
document.put("apiParamDesc", jsonObject.toString());
table.insert(document);
It is inserting data in this way.
{ "_id" : { "$oid" : "534251125f1ab7ec747298cd"} , "apiKey" : "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6" , "apiParamDesc" : "{\"param0\":\"Car Make\",\"param1\":\"Car Model\",\"param2\":\"Car Variant\",\"param3\":\"Car Year\",\"param4\":\"Car Number\"}"}
Now i want to get apiParamDesc value using apiKey. Like how we get data in mysql.
Select apiParamDesc where apiKey =
'1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6';
I googled a lot but could not found anything. This is how i am trying to get this apiParamDesc
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6");
DBCursor cursor = table.find(whereQuery);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
But this is giving me entire row. I want only apiParamDesc in a String.
Please help me.
Thanks
You can easily do it with aggregation framework. Below is the example which can resolve your issue:
// create our pipeline operations, first with the $match
DBObject match = new BasicDBObject("$match", new BasicDBObject("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6"));
// build the $projection operation
DBObject fields = new BasicDBObject("apiParamDesc", 1);
fields.put("_id", 0);
DBObject project = new BasicDBObject("$project", fields );
// run aggregation
AggregationOutput output = collection.aggregate( match, project);
You can also make use of only db.coll.find(< criteria >, < projection >);
BasicDBObject query = new BasicDBObject(new BasicDBObject("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6"), new BasicDBObject("apiParamDesc", 1).append("_id", 0));
//Which is equivalent to a follwoing query
//'db.coll.find({"apiKey": "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6"}, {"apiParamDesc": 1,"_id": 0});'
cursor = coll.find(query);
One more thing to update you on "I want only apiParamDesc in a String.", is if you are storing string like
"apiParamDesc" : "{\"param0\":\"Car Make\",\"param1\":\"Car Model\",\"param2\":\"Car Variant\",\"param3\":\"Car Year\",\"param4\":\"Car Number\"}
You cannot query on those sub level fields like param0, param1 ...
You data should look like :
{
"_id":{
"$oid":"534251125f1ab7ec747298cd"
},
"apiKey":"1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6",
"apiParamDesc":{
"param0":"Car Make",
"param1":"Car Model",
"param2":"Car Variant",
"param3":"Car Year",
"param4":"Car Number"
}
}
I want only apiParamDesc in a String.
You cannot however, you can get a document (object) returned with only the apiParamDesc as its single field (my Java is rusty):
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6");
BasicDBObject fields = new BasicDBObject();
fields.put("apiParamDesc", 1);
fields.put("_id", 0);
DBCursor cursor = table.find(whereQuery, fields);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
I am quite new to MongoDb. i use a find and get the result in JSON format.
{"Name": "Harshil", "Age":20}
so what i need is parse this in java and get values in the variables.
String name should contain Harshil
int age should contain 20
is there a way to store these details in JAVA object?
Here is how to connect to the your MongoDB:
MongoClient client = new MongoClient("localhost",27017); //with default server and port adress
DB db = client.getDB( "your_db_name" );
DBCollection collection = db.getCollection("Your_Collection_Name");
After the connecting you can pull your data from the server.Below, i assume that your document has Name and Age field :
DBObject dbo = collection.findOne();
String name = dbo.get("Name");
int age = dbo.get("Age");
Take a look at GSON library. It converts JSON to Java objects and vice-versa.
There are many ways and tools, one of which is gson
class Person {
private String name;
private int age;
public Person() {
// no-args constructor
}
}
Gson gson = new Gson();
Person person = gson.fromJson(json, Person.class);
And I'd feel lax if I didn't add this link too.
You can just do it with the Java driver :
DBObject dbo = ...
String s = dbo.getString("Name")
int i = dbo.getInt("Age")
Using another framework on top of the Java driver should be considered I you have multiple objects to manage.
As we don't want to use the deprecated methods so, you can use the following code to do so:
MongoClient mongo = new MongoClient( "localhost" , 27017 );
MongoDatabase database = mongo.getDatabase("your_db_name");
MongoCollection<Document> collection = database.getCollection("your_collection_name");
FindIterable<Document> iterDoc = collection.find();
MongoCursor<Document> dbc = iterDoc.iterator();
while(dbc.hasNext()){
try {
JsonParser jsonParser = new JsonFactory().createParser(dbc.next().toJson());
ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue(jsonParser, Person.class);
String name = person.get("Name");
String age = person.get("Age");
} catch (Exception e){
e.printStackTrace();
}
JsonFactory, JsonParser,etc. are being used from Jackson to de-serialize the Document to the related Entity object.
Have you considere Morphia?
#Entity
class Person{
#Property("Name") Date name;
#Property("Age") Date age;
}
I would prefer using the new Mongodb Java API. It's very clean and clear.
public MyEntity findMyEntityById(long entityId) {
List<Bson> queryFilters = new ArrayList<>();
queryFilters.add(Filters.eq("_id", entityId));
Bson searchFilter = Filters.and(queryFilters);
List<Bson> returnFilters = new ArrayList<>();
returnFilters.add(Filters.eq("name", 1));
Bson returnFilter = Filters.and(returnFilters);
Document doc = getMongoCollection().find(searchFilter).projection(returnFilter).first();
JsonParser jsonParser = new JsonFactory().createParser(doc.toJson());
ObjectMapper mapper = new ObjectMapper();
MyEntity myEntity = mapper.readValue(jsonParser, MyEntity.class);
return myEntity;
}
Details at
http://ashutosh-srivastav-mongodb.blogspot.in/2017/09/mongodb-fetch-operation-using-java-api.html
Newer Way [Since getDB() is Deprecated]
Since the original answer was posted the DBObject and corresponding method client.getDB have been deprecated. For anyone who may be looking for a solution since the new update I have done my best to translate.
MongoClient client = new MongoClient("localhost",27017); //Location by Default
MongoDatabase database = client.getDatabase("YOUR_DATABASE_NAME");
MongoCollection<Document> collection = database.getCollection("YOUR_COLLECTION_NAME");
Once connected to the document there are numerous familiar methods of getting data as a Java Object. Assuming you plan to have multiple documents that contain a persons name and their age I suggest collecting all the documents (which you can visualize as rows containing a name and age) in an ArrayList then you can simply pick through the documents in the ArrayList to convert them to java objects as so:
List<Document> documents = (List<Document>) collection.find().into(new ArrayList<Document>());
for (Document document : documents) {
Document person = documents.get(document);
String name = person.get("Name");
String age = person.get("Age");
}
Honestly the for loop is not a pretty way of doing it but I wanted to help the community struggling with deprecation.
Try Using this function to convert JSON returned by mongodb to your custom java object list.
MongoClient mongodb = new MongoClient("localhost", 27017);
DB db = mongodb.getDB("customData-database");
DBCursor customDataCollection = db.getCollection("customDataList").find();
List<CustomJavaObject> myCustomDataList = null; // this list will hold your custom data
JSON json = new JSON();
ObjectMapper objectMapper = new ObjectMapper();
try {
//this is where deserialiazation(conversion) takes place
myCustomDataList = objectMapper.readValue(json.serialize(customDataCollection),
new TypeReference<List<Restaurant>>() {
});
} catch (IOException e) {
e.printStackTrace();
}
CustomJavaObject:
public class CustomJavaObject{
//your json fields go here
String field1, field2;
int num;
ArrayList<String> attributes;
//....write relevantgetter and setter methods
}
sample json:
{
"field1": "Hsr Layout",
"field2": "www.google.com",
"num": 20,
"attributes": [
"Benagaluru",
"Residential"
]
},
{
"field1": "BTM Layout",
"field2": "www.youtube.com",
"num": 10,
"attributes": [
"Bangalore",
"Industrial"
]
}
Is there an easy way to get the ID (ObjectID) of the last inserted document of a mongoDB instance using the Java driver?
I just realized you can do this:
BasicDBObject doc = new BasicDBObject( "name", "Matt" );
collection.insert( doc );
ObjectId id = (ObjectId)doc.get( "_id" );
To avoid casting from Object to ObjectId, given a com.mongodb.client.MongoCollection collection and a org.bson.Document doc, you can do the following:
collection.insert(doc);
ObjectId id = doc.getObjectId("_id");
It's safe to do
doc.set("_id", new ObjectId())
if you look at driver code
if ( ensureID && id == null ){
id = ObjectId.get();
jo.put( "_id" , id );
}
public static ObjectId get(){
return new ObjectId();
}
I do not know about the Java driver but for posterity, the getLastError command can be run to get the _id of a write, even an upsert (as of 1.5.4)
After a document is inserted into the MongoDB collection, the successful insertion should update required fields (viz. _id). You may query the inserted object for the _id.
In MongoTemplate.class has a method
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
assertUpdateableIdIfNotSet(objectToSave);
initializeVersionProperty(objectToSave);
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
DBObject dbDoc = toDbObject(objectToSave, writer);
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc, collectionName));
Object id = insertDBObject(collectionName, dbDoc, objectToSave.getClass());
populateIdIfNecessary(objectToSave, id);
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc, collectionName));
}
and the method will set id for us
protected void populateIdIfNecessary(Object savedObject, Object id) {
if (id == null) {
return;
}
if (savedObject instanceof BasicDBObject) {
DBObject dbObject = (DBObject) savedObject;
dbObject.put(ID_FIELD, id);
return;
}
MongoPersistentProperty idProp = getIdPropertyFor(savedObject.getClass());
if (idProp == null) {
return;
}
ConversionService conversionService = mongoConverter.getConversionService();
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(savedObject.getClass());
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject);
if (accessor.getProperty(idProp) != null) {
return;
}
new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, id);
}
we can see if the entity is a sub-class of BasicDBObject,it will set a id for us.
I think the answer to this is "No".
What you can do is provide your the _id yourself, either manually, or implement the CollectibleCodec mechanism (which is exactly what BasicBDDocument does). However all these solutions involve generating the ID clientside.
Having said that, I don't think there's any problem with generating the _id clientside.
This is insert operation:
DBCollection table1 = db.getCollection("Collection name");
BasicDBObject document = new BasicDBObject();
document.put("_id",value);
document.put("Name", name);
table1.insert(document);
After insert u get last inserted id:
DBCollection tableDetails = db.getCollection("collection name");
BasicDBObject queryDetails = new BasicDBObject();
queryDetails.put("_id", value);
DBCursor cursorDetails =tableDetails.find(queryDetails);
DBObject oneDetails;
oneDetails=cursorDetails.next();
String data=oneDetails.get("_id").toString();
System.out.println(data);
after getting value convert to inter type.