how can i create a dynamic Model/Object for the dataobject - java

I am trying to get the Data from Mongodb whose Model/Domain is unknown.
Can i get that using Mongo Template.
e.g.
mongoTemplate.find(query,<Dynamic Class?>)

You can use DBObject. If you take a look at its implementations (BasicDBObject...) it's an HashMap (key/values) containing all fields:
#Autowired
private MongoTemplate mongoTemplate;
DBObject query = new BasicDBObject("field", "value");
DBCursor dbCursor = mongoTemplate.getCollection("collectionName").find(query);
Iterator<DBObject> iterator = dbCursor.iterator();
while(iterator.hasNext()){
Object value = iterator.next().get("otherfield");
}

Related

Insert an ArrayList to mongoDB in Java

I'm trying to insert a single ArrayList containing JSONS into a mongodb collection with this,
MongoClient mongo = new MongoClient("localhost", 27017);
DB db = mongo.getDB("structure");
DBCollection collection = db.getCollection("chapter");
List<Document> data = new ArrayList<>();
collection.insertMany(data);
String str = "[{\"id\":1,\"data\":\"data1\"},{\"id\":2,\"data\":\"data2\"}]";
DBObject dbObject = (DBObject) JSON.parse(str);
collection.insert(dbObject);
But I get the exception,
Exception in thread "main" java.lang.IllegalArgumentException: BasicBSONList can only work with numeric keys, not: [_id]
Can anyone show me the correct way to do this?
Insert ArrayList mongodb
The question above is about bulk insert of JSONS, not as a single one.
My question is unique
The exception gives a hint of what the problem is: a list cannot be used as a record (or a map-like data structure).
To quote the MongoDB documentation on documents that compose a collection:
Document Structure
MongoDB documents are composed of field-and-value
pairs and have the following structure:
{
field1: value1,
field2: value2,
field3: value3,
...
fieldN: valueN
}
So what you need to do, in your case, because you just want to insert many documents in one call, is to use collection.insertMany:
List<Document> documents = ...; //convert your list to a List<Document>
collection.insertMany(documents);
Have a look at this
https://docs.mongodb.com/manual/reference/method/db.collection.insertMany/
List<DBobject> data = new ArrayList<>();
Colletions.insertMany(data);

Is there any way to update/replace whole document of mongoDB from java using mongoDB morphia?

I need to replace a whole existing document of mongodb from java instead of setting every field.Is there any way? I am using mongo morphia.
Right now i am setting fields one by one ,following is code :
DBObject searchObject =new BasicDBObject();
searchObject.put("procId", procId);
final UpdateOperations<Timesheet> updateOperations = ds.createUpdateOperations(Timesheet.class)
.set("wheelInTime", timesheet.getWheelInTime())
.set("wheelOutTime", timesheet.getWheelOutTime())
.set("tableOnTime", timesheet.getTableOnTime())
.set("tableOffTime", timesheet.getTableOffTime())
final UpdateResults results = ds.updateFirst(findQuery,updateOperations);
You can 'overwrite' any entry in a MongoDB collection but simply creating a new DbObject with the same _id field and saving it to the database. So just set the fields in your object as you would any Java object and use myCollection.save(obj)
Just save the object and it will overwrite the document with the same #id. This can be done with one line of code:
dao.save(timesheet);
More complete example code of the usage of the Morphia DAO:
class Dao extends BasicDAO<TimeSheet, String> {
Dao(Datastore ds) {
super(TimeSheet.class, ds);
}
}
Datastore ds = morphia.createDatastore(mongoClient, DB_NAME);
Dao dao = new Dao(ds);
dao.save(timesheet);

Streaming the result of an aggregate operation using spring-data-mongodb

I am using spring-data-mongodb and I want to use a cursor for an aggregate operation.
MongoTemplate.stream() gets a Query, so I tried creating the Aggregation instance, convert it to a DbObject using Aggregation.toDbObject(), created a BasicQuery using the DbObject and then invoke the stream() method.
This returns an empty cursor.
Debugging the spring-data-mongodb code shows that MongoTemplate.stream() uses the FindOperation, which makes me thinkspring-data-mongodb does not support streaming an aggregation operation.
Has anyone been able to stream the results of an aggregate query using spring-data-mongodb?
For the record, I can do it using the Java mongodb driver, but I prefer using spring-data.
EDIT Nov 10th - adding sample code:
MatchOperation match = Aggregation.match(Criteria.where("type").ne("AType"));
GroupOperation group = Aggregation.group("name", "type");
group = group.push("color").as("colors");
group = group.push("size").as("sizes");
TypedAggregation<MyClass> agg = Aggregation.newAggregation(MyClass.class, Arrays.asList(match, group));
MongoConverter converter = mongoTemplate.getConverter();
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = converter.getMappingContext();
QueryMapper queryMapper = new QueryMapper(converter);
AggregationOperationContext context = new TypeBasedAggregationOperationContext(MyClass.class, mappingContext, queryMapper);
// create a BasicQuery to be used in the stream() method by converting the Aggregation to a DbObject
BasicQuery query = new BasicQuery(agg.toDbObject("myClass", context));
// spring-mongo attributes the stream() method to find() operationsm not to aggregate() operations so the stream returns an empty cursor
CloseableIterator<MyClass> iter = mongoTemplate.stream(query, MyClass.class);
// this is an empty cursor
while(iter.hasNext()) {
System.out.println(iter.next().getName());
}
The following code, not using the stream() method, returns the expected non-empty result of the aggregation:
AggregationResults<HashMap> result = mongoTemplate.aggregate(agg, "myClass", HashMap.class);
For those who are still trying to find the answer to this:
From spring-data-mongo version 2.0.0.M4 onwards (AFAIK) MongoTemplate got an aggregateStream method.
So you can do the following:
AggregationOptions aggregationOptions = Aggregation.newAggregationOptions()
// this is very important: if you do not set the batch size, you'll get all the objects at once and you might run out of memory if the returning data set is too large
.cursorBatchSize(mongoCursorBatchSize)
.build();
data = mongoTemplate.aggregateStream(Aggregation.newAggregation(
Aggregation.group("person_id").count().as("count")).withOptions(aggregationOptions), collectionName, YourClazz.class);

How to return raw JSON directly from a mongodb query in Java?

I have the following code:
#RequestMapping(value = "/envinfo", method = RequestMethod.GET)
#ResponseBody
public Map getEnvInfo()
{
BasicQuery basicQuery = new BasicQuery("{_id:'51a29f6413dc992c24e0283e'}", "{'envinfo':1, '_id': false }");
Map envinfo= mongoTemplate.findOne(basicQuery, Map.class, "jvmInfo");
return envinfo;
}
As you can notice, the code:
Retrieves JSON from MongoDB
Converts it to a Map object
The Map object is then converted to JSON by Spring MongoData before it is returned to the browser.
Is it possible to directly return the raw json from MongoDb without going through the intermediate conversion steps?
There's two way's you can do this right now:
1. Using the CollectionCallback on MongoTemplate
You can use a CollectionCallback to deal with the returned DBObject directly and simply toString() it:
template.execute("jvmInfo", new CollectionCallback<String>() {
String doInCollection(DBCollection collection) {
DBCursor cursor = collection.find(query)
return cursor.next().toString()
}
}
Yo'll still get the exception translation into Spring's DataAccessExceptions. Note, that this is slightly brittle as we expect only a single result to be returned for the query but that's probably something you have to take care of when trying to produce a String anyway.
2. Register a Converter from DBObject to String
You can implement a Spring Converter to do the toString() for you.
class DBObjectToStringConverter implements Converter<DBObject, String> {
public String convert(DBObject source) {
return source == null ? null : source.toString();
}
}
You can then either use the XML configuration or override customConversions() to return a new CustomConversions(Arrays.asList(new DBObjectToStringConverter())) to get it registered with your MongoConverter. You can then simply do the following:
String result = mongoTemplate.findOne(basicQuery, String.class, "jvmInfo");
I will add the just showed converter to Spring Data MongoDB and register it by default for the upcoming 1.3 GA release and port the fix back to 1.2.x as part of the fix for DATAMONGO-743.
As Oliver points out, you can use Spring Data for that, but an alternative which you may or may not prefer would be to use MongoDB's more low-level Java Driver. Take a look at the MongoDB Java Driver 3.x or MongoDB Java Driver 2.x documentation for instructions on using that driver.
Basically, what you need to do is this:
MongoDB Java Driver 3.x
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("test");
MongoCollection coll = db.getCollection("testCollection");
BasicDBObject query = new BasicDBObject("_id", "51a29f6413dc992c24e0283e");
try (MongoCursor<Document> cursor = collection.find(query).iterator()) {
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
}
MongoDB Java Driver 2.x
MongoClient mongoClient = new MongoClient();
DB db = mongoClient.getDB("test");
DBCollection coll = db.getCollection("testCollection");
BasicDBObject query = new BasicDBObject("_id", "51a29f6413dc992c24e0283e");
try (DBCursor cursor = coll.find(query)) {
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
}
That will print out all the documents in the collection that have a field _id with a value 51a29f6413dc992c24e0283e.
For me the following worked perfectly:
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.bson.Document;
List<Document> documents = mongoTemplate.find(query, Document.class, "collection_name");

Mongo Database save data from Map

I have the below code which works:
if (aDBCursor.hasNext()) {
DBObject aDbObject = aDBCursor.next();
aDbObject.put("title", "Test Title");
ArrayList<DBObject> department = new ArrayList<DBObject>();
DBObject nested1 = new BasicDBObject();
nested1.put("name", "Department A");
nested1.put("id", 1);
department.add(nested1);
DBObject nested2 = new BasicDBObject();
nested2.put("name", "Department B");
nested2.put("id", 2);
department.add(nested2);
aDbObject.put("department", department);
collection.save(aDbObject);
}
However I have the data for Department A and B in a map like:
Map<Object,Object> map = new HashMap<Object,Object>();
map.put("1", "Department A");
map.put("2", "Department B");
What would the best/easiest way be to save this data? Is there a way to put the map straight into the mongo DB? Or would I have to loop over the map?
The data that goes into the map already is taken from the database like so:
String[] values = req.getParameterValues("departments");
Map<Object,Object> map = new HashMap<Object,Object>();
DBCollection collection = database.getCollection("Departments");
BasicDBObject query = new BasicDBObject();
query.put("id", new BasicDBObject("$in", values));
DBCursor cursor = collection.find(query);
Would be even better is I could just put the DBCursor object back into the database.
Any ideas?
Thanks for any help or suggestions!
Native Java types (int, float, String, Date, Map, etc) will get automatically encoded to the right BSON type, so you can use a BasicDBObject to put the Map straight into the mongo collection:
// you probably want to be more specific with your generics than Object!
Map<Object,Object> map = new HashMap<Object,Object>();
map.put("1", "Department A");
map.put("2", "Department B");
collection.insert(new BasicDBObject(map));
However, it looks like your Map doesn't actually have the structure that you want, so you need some kind of mapping to the desired structure. Either use the basic mapping that's built into the java driver (you're on the right track by calling BasicDBObject.put, and here are some more ideas), or use something like Morphia for extended mapping.
Ok guys, I got it working.
String[] values = req.getParameterValues("departments");
Map<Object,Object> map = new HashMap<Object,Object>();
DBCollection collection = database.getCollection("Departments");
BasicDBObject query = new BasicDBObject();
query.put("id", new BasicDBObject("$in", values));
DBCursor cursor = collection.find(query);
if(aDBCursor.hasNext()){
DBObject aDbObject=aDBCursor.next();
aDbObject.put("title", "Test Title");
aDbObject.put("department", cursor);
collection.save(aDbObject);
}
As simple as that!
Thanks for all your replies and suggestions!
What would the best/easiest way be to save this data? Is there a way to put the map straight into the mongo DB? Or would I have to loop over the map?
Map can be directly added to a BasicDBObject through constructor itself.This can directly be inserted into db without iterating.
Would be even better is I could just put the DBCursor object back into the database.
DBCursor implements iterator, so it cannot be put back in db without iterating

Categories