How to get value from Embedded Key of MongoDB using Java? - mongodb

I want to extract value of a embedded key(detokenObject.0.client.COUNTRY) from Mongodb document using java.
I have tried below piece of code.
DBCursor cursor1 = coll1.find();
while (cursor1.hasNext()) {
BasicDBObject dbObject = (BasicDBObject)cursor1.next();
BasicDBObject dbObject1= ((BasicDBObject)dbObject.get("detokenObject"));
BasicDBObject dbObject2= ((BasicDBObject)dbObject1.get("0"));
System.out.println("value is:::"+((BasicDBObject)dbObject2.get("client")).get("COUNTRY"));
}
But after running this, getting ClassCastException(com.mongodb.BasicDBList cannot be cast to com.mongodb.BasicDBObject)
any solution?

The error ClassCastException(com.mongodb.BasicDBList cannot be cast to com.mongodb.BasicDBObject) says it all, you are trying to cast a BasicDBList to BasicDBObject on detokenObject field, which is a list.
Use
BasicDBList dbList = (BasicDBList) dbObject.get("detokenObject");
instead of
BasicDBObject dbObject1 = ((BasicDBObject)dbObject.get("detokenObject"));
and then get its element client value by its index with dbList.getIndex(0);
i.e. your final code should look like:
DBCursor cursor1 = coll1.find();
while (cursor1.hasNext()) {
BasicDBObject dbObject = (BasicDBObject) cursor1.next();
BasicDBObject dbList = (BasicDBList) dbObject.get("detokenObject");
BasicDBObject dbObject1= (BasicDBObject) dbList.getIndex(0);
System.out.println("value is::: " + (BasicDBObject) dbObject1.get("client")
.get("COUNTRY"));
}

I have tried below solution to chained the keys and it worked for me.
public static Object getField(DBObject obj, String fieldName) {
String[] fieldSections =fieldName.split("\\.");
int i = 1;
Object value = obj.getfieldSections[0]);
while(i < fieldSections.length && value instanceof DBObject) {
value = ((DBObject)value).get(fieldSections[i]);
i++;
}
return value;
}

Related

how should migrate my DBRef fields with mongock?

I have a problem with migrating an entity which has DBRef fields. If I change any field in this entity, my DBRefs are gone. What should I do?
Query query = new Query();
List<Criteria> criteriaList = new ArrayList<Criteria>();
criteriaList.add(Criteria.where("created").exists(false));
criteriaList.add(Criteria.where("updated").exists(false));
query.addCriteria(new Criteria().orOperator(criteriaList.toArray(new Criteria[criteriaList.size()])));
List<Asset> results = mongoTemplate.find(query, Asset.class);
results.forEach(asset -> {
asset.setCreated(asset.getCreatedBy().getCreated());
mongoTemplate.save(asset);
});
in summary, its problem is the MongoTemplate. mongoTemplate.save(...) creates a new entity and saves it to DB. As a consequence, if you want to change/update a field in your entity, you should use mongoTemplate.updateFirst(...). My solution is as the following.
public void createAssetCreateOrUpdateDateIfNot(MongockTemplate mongockTemplate) {
MongoTemplate mongoTemplate = mongockTemplate.getImpl();
Query queryGetAssetsCreatedOrUpdatedIsNot = new Query();
List<Criteria> criteriaList = new ArrayList<Criteria>();
criteriaList.add(Criteria.where("created").exists(false));
criteriaList.add(Criteria.where("updated").exists(false));
queryGetAssetsCreatedOrUpdatedIsNot
.addCriteria(new Criteria().orOperator(criteriaList.toArray(new Criteria[criteriaList.size()])));
List<Asset> results = mongoTemplate.find(queryGetAssetsCreatedOrUpdatedIsNot, Asset.class);
if (results.size() > 0) {
for (Asset asset : results) {
Date createdDate = (asset.getCreatedBy().getCreated() != null)
? asset.getCreatedBy().getCreated()
: new Date();
Date updateDate = (asset.getModifiedBy().getCreated() != null)
? asset.getModifiedBy().getCreated()
: new Date();
Query queryGetAssetViaId = new Query();
queryGetAssetViaId.addCriteria(Criteria.where("id").is(asset.getId()));
Update update = new Update()
.set("created", createdDate)
.set("updated", updateDate);
mongoTemplate.updateFirst(queryGetAssetViaId, update, Asset.class);
}
}
}

spring boot not able to retrieve gridfs

So I have been trying for hours or even the whole day on how to retrieve my gridfs from the mongodb.
This is how I save it:
DBObject dbObject = new BasicDBObject();
Map<String, Boolean> values = new HashMap<>();
values.put("boolean", true);
dbObject.put("tags", tags);
dbObject.put("description", des);
Object id = gridFsTemplate.store(file.getInputStream(), String.valueOf(file.getName()), dbObject);
Query query = new Query();
query.addCriteria(Criteria.where("email").is(jwt.extractEmail(token)));
Update update = new Update();
if(repository.findByEmail(jwt.extractEmail(token)) == null){
update.set("gridFsId", Arrays.asList(id.toString()));
}
else{
User user = repository.findByEmail(jwt.extractEmail(token));
List<String> gridFsId = user.gridFsId;
gridFsId.add(id.toString());
update.set("gridFsId", gridFsId);
}
template.updateMulti(query, update, User.class);
values.put("boolean", true);
return values;
and this is how I try to get it:
public List<item> get_items(String token){
User user = repository.findByEmail(jwt.extractEmail(token));
List<GridFSFile> items = new ArrayList<>();
}
for some reason whenever I try to use GridFSDBFile the whole line is read.
Please help ;)

Update the subDcoument attribute

I have a document having schema like bellow
{
"Personal":[
{
"name":"Test_Name",
"isActive":true
}
]
}
am trying to update this as below using java driver.
collections.updateMany(new Document("Personal.name", "Test_Name"), new Document("$set", new Document("Personal.$.isActive", false)))
But unfortunately this trows an error
"The positional operator did not find the match needed from the query. Unexpanded update: Personal.$.isActive"
But if i modify the above update filter something like
collections.updateMany(new Document("Personal.name", "Test_Name"), new Document("$set", new Document("Personal.0.isActive", false)))
it works.
Can any one help me in understanding whats wrong in using "$" in my 1st update statement?
Here is some more code spinets
Creating the collection object:
collections = mongoConnection.establishConnection()
MongoConnection object:
public MongoConnection() {
StringBuilder connectionString = new StringBuilder();
connectionString.append("mongodb://url_with_port_and_server")
client = new MongoClient(new MongoClientURI(connectionString.toString()));
db = client.getDatabase("test");
collections = db.getCollection("test");
}
public MongoCollection<Document> establishConnection() {
return collections;
}
public void closeConnection() {
client.close();
}

Spring data mongodb aggregation scenario

How can I translate
$group : {
_id : 1 ,
likes : { $avg: { $size: ["$likes"] }},
count: { $sum: 1 },
}
into a spring-data-mongodb aggregation query?
You can use Following Code :
ArrayList<String> list = new ArrayList<>();
list.add("$likes");
BasicDBObject idObj = new BasicDBObject("_id", 1);
BasicDBObject likesObj = new BasicDBObject("$avg", new BasicDBObject("$size", list));
BasicDBObject countObj = new BasicDBObject("$sum", 1);
idObj.append("likes", likesObj).append("count", countObj);
BasicDBObject group = new BasicDBObject("$group", idObj);
List<DBObject> pipeline = new ArrayList<>();
pipeline.add(group);
MongoTemplate mongoTemplate = new MongoTemplate(new MongoClient(), "dbname");
AggregationOutput aggregationOutput = mongoTemplate.getCollection("collectionName")
.aggregate(pipeline);
List<DBObject> dbObjects = (List<DBObject>) aggregationOutput.results();
//convert dbObjects into appropriate output
You can use also following way for spring data mongodb
List<AggregationOperation> stages = new ArrayList<>();
GroupOperation groupOperation = group()
.count().as("count")
.avg(ArrayOperators.Size.lengthOfArray("likes")).as("likes");
stages.add(groupOperation);
AggregationResults<ResultDTO> result = mongoOperation.aggregate(newAggregation(stages),
"collectionName", ResultDTO.class);
public class ResultDTO {
private Integer count;
private Double likes;
//getter setter
}

How to retrieve an embedded list of object of Entity?

I have a simple problem storing and retrieving an embedded collection of entity to mongo. I have checked theses question :
how to serialize class? and Mongodb saves list of object
what I understand is to save a list objects the class of that objects must extends ReflactionDBObject. This worked for saving the object, by retrieving it with the embedded collection does not work.
here a simple test show that retrieving embedded entities does not work !
#Test
public void whatWasStoredAsEmbeddedCollectionIsRetrieved2() {
BasicDBObject country = new BasicDBObject();
country.put("name", "Bulgaria");
List<City> cities = Lists.newArrayList(new City("Tarnovo"));
country.put("listOfCities", cities);
DBCollection collection = db().get().getCollection("test_Collection");
collection.save(country);
DBCursor object = collection.find(new BasicDBObject().append("name", "Bulgaria"));
DBObject returnedCity = object.next();
DBObject embeddedCities = (DBObject) returnedCity.get("listOfCities");
System.out.println(embeddedCities);
}
Here is the City Class
class City extends ReflectionDBObject {
String name;
City() {
}
City(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof City)) return false;
City city = (City) o;
if (name != null ? !name.equals(city.name) : city.name != null) return false;
return true;
}
#Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
#Override
public String toString() {
return "City{" +
"name='" + name + '\'' +
'}';
}
}
The out put of the System.out.println statement is [ { "_id" : null }]
Now how can get back the embedded object and the embedded list in it ?
If you do not have a requirement to define your own class City, you can define subdocuments using the BasicDBObjects. I only added the 'name' field to the citySubDoc1 and citySubDoc2, but of course, you can add more fields to these subdocuments.
// Define subdocuments
BasicDBObject citySubDoc1 = new BasicDBObject();
citySubDoc1.put("name", "Tarnovo");
BasicDBObject citySubDoc2 = new BasicDBObject();
citySubDoc2.put("name", "Sofia");
// add to list
List<DBObject> cities = new ArrayList <DBObject>();
cities.add(citySubDoc1);
cities.add(citySubDoc2);
country.put("listOfCities", cities);
collection.save(country);
// Specify query condition
BasicDBObject criteriaQuery = new BasicDBObject();
criteriaQuery.put("name", "Bulgaria");
// Perform the read
DBCursor cursor = collection.find(criteriaQuery);
// Loop through the results
try {
while (cursor.hasNext()) {
List myReturnedListOfCities = (List) cursor.next().get("listOfCities");
System.out.println(myReturnedListOfCities);
}
} finally {
cursor.close();
}