Mongo Database save data from Map - java

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

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);

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

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");
}

MongoDB-Java: How to make $geoNear to first do query, then distance?

I'm trying to query and sort documents as followed:
Query only for documents older than SOMETIME.
Within range of AROUNDME_RANGE_RADIUS_IN_RADIANS.
Get distance for each document.
Sort them by time. New to Old.
Overall it should return up to 20 results.
But it seems that since $geoNear is by default limited to 100 results, I get unexpected results.
I see $geoNear working in the following order:
Gets docs from the entire collection, by distance.
And only then executes the given Query.
Is there a way to reverse the order?
MongoDB v2.6.5
Java Driver v2.10.1
Thank you.
Example document in my collection:
{
"timestamp" : ISODate("2014-12-27T06:52:17.949Z"),
"text" : "hello",
"loc" : [
34.76701564815013,
32.05852053407342
]
}
I'm using aggregate since from what I understood it's the only way to sort by "timestamp" and get the distance.
BasicDBObject query = new BasicDBObject("timestamp", new BasicDBObject("$lt", SOMETIME));
// aggregate: geoNear
double[] currentLoc = new double[] {
Double.parseDouble(myLon),
Double.parseDouble(myLat)
};
DBObject geoNearFields = new BasicDBObject();
geoNearFields.put("near", currentLoc);
geoNearFields.put("distanceField", "dis");
geoNearFields.put("maxDistance", AROUNDME_RANGE_RADIUS_IN_RADIANS));
geoNearFields.put("query", query);
//geoNearFields.put("num", 5000); // FIXME: a temp solution I would really like to avoid
DBObject geoNear = new BasicDBObject("$geoNear", geoNearFields);
// aggregate: sort by timestamp
DBObject sortFields = new BasicDBObject("timestamp", -1);
DBObject sort = new BasicDBObject("$sort", sortFields);
// aggregate: limit
DBObject limit = new BasicDBObject("$limit", 20);
AggregationOutput output = col.aggregate(geoNear, sort, limit);
You could add a $match stage at the top of the pipleine, to filter the documents before the $geonear stage.
BasicDBObject match = new BasicDBObject("timestamp",
new BasicDBObject("$lt", SOMETIME));
AggregationOutput output = col.aggregate(match,geoNear, sort, limit);
The below piece of code now, is not required,
geoNearFields.put("query", query);

get some attributes from mongodb except one or two

I would like to get some information which is in a mongoDB except some attributes.
I tried it in cmd and it worked:
db.orders.find({name:"chabeee"},{_id:0, name:1, worksAt:1})
Then I get this result:
{ "name" : "chabeee", "worksAt" : "jobAtBp" }
{ "name" : "chabeee", "worksAt" : "jobAtRE" }
Its okay, but I want to get in a Java Program. How can I do that?
You have to create one additional BasicDBObject, which will be used for pointing out which exact keys to be fetched. And finally the DBCollection#find(DBObject ref, DBObject keys) method has to be invoked in order to pass the desired projection keys.
BasicDBObject query = new BasicDBObject("name", "chabeee");
BasicDBObject keys = new BasicDBObject();
keys.put("_id", 0);
keys.put("name", 1);
keys.put("worksAt", 1);
BasicDBCursor result = collection.find(query, keys);
Then you just have to iterate over the BasicDBCursor and verify the result.
while (cursor.hasNext()) {
System.out.println(cursor.next());
}

How to update value of specific embedded document, inside an array, of a specific document in MongoDB?

I have the following structure in my document:
{
_id : ObjectId("43jh4j343j4j"),
array : [
{
_arrayId : ObjectId("dsd87dsa9d87s9d7"),
someField : "something",
someField2 : "something2"
},
{
_arrayId : ObjectId("sds9a0d9da0d9sa0"),
someField : "somethingElse",
someField2 : "somethingElse2"
}
]
}
I want to update someField and someField2 but only for one of the items in the array, the one that matches _arrayId (e.g. _arrayId : ObjectId("dsd87dsa9d87s9d7"); and only for this document (e.g. _id : ObjectId("43jh4j343j4j") ) and no other.
The arrayIds are not unique to the document that's why I need it to be for a specific document. I could use the $ positional operator if I wanted to update that value within the array for every document it exists in, but that's not what I want.
I am trying to accomplish this in java but a command line solution would work as well.
Here is RameshVel's solution translated to java:
DB db = conn.getDB( "yourDB" );
DBCollection coll = db.getCollection( "yourCollection" );
ObjectId _id = new ObjectId("4e71b07ff391f2b283be2f95");
ObjectId arrayId = new ObjectId("4e639a918dca838d4575979c");
BasicDBObject query = new BasicDBObject();
query.put("_id", _id);
query.put("array._arrayId", arrayId);
BasicDBObject data = new BasicDBObject();
data.put("array.$.someField", "updated");
BasicDBObject command = new BasicDBObject();
command.put("$set", data);
coll.update(query, command);
You could still use $ positional operator to accomplish this. But you need to specify the objectid of the parent doc along with the _arrayid filter. The below command line query works fine
db.so.update({_id:ObjectId("4e719eb07f1d878c5cf7333c"),
"array._arrayId":ObjectId("dsd87dsa9d87s9d7")},
{$set:{"array.$.someField":"updated"}})
...and this is how to do it with mongo-driver version >= 3.1 (mine is 3.2.2):
final MongoClient mongoClient = new MongoClient(new MongoClientURI(mongoURIString));
final MongoDatabase blogDatabase = mongoClient.getDatabase("yourDB");
MongoCollection<Document> postsCollection = blogDatabase.getCollection("yourCollection");
ObjectId _id = new ObjectId("4e71b07ff391f2b283be2f95");
ObjectId arrayId = new ObjectId("4e639a918dca838d4575979c");
Bson filter = Filters.and(Filters.eq( "_id", id ), Filters.eq("array._arrayId", arrayId));
Bson setUpdate = Updates.set("array.$.someField", "updated");
postsCollection.updateOne(postFilter, setUpdate);
Seeing as none of the answers actually explain how to do this a) in Java and b) for multiple fields in a nested array item, here is the solution for mongo-java-driver 3.12.3.
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import org.bson.types.ObjectId;
MongoClient mongoClient = MongoClients.create(...);
MongoDatabase db = mongoClient.getDatabase("testDb");
MongoCollection<Document> collection = db.getCollection("testCollection");
collection.updateOne(
Filters.and(
Filters.eq("_id", new ObjectId("43jh4j343j4j")),
Filters.eq("array._arrayId", new ObjectId("dsd87dsa9d87s9d7"))
),
Updates.combine(
Updates.set("array.$.someField", "new value 1"),
Updates.set("array.$.someField2", "new value 2")
)
);
This thread has helped me towards the right solution, but I had to do more research for the full solution, so hoping that someone else will benefit from my answer too.

Categories