how should migrate my DBRef fields with mongock? - mongodb

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

Related

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

Get multiple list grouped by different fields

I'm using this method to send multiple list to client.
public ResponseEntity<?> getFiveLastRequestOfEachVehicleType() {
ResponseContent content = getResponseContent();
Map<String, List<Request>> map = new HashMap<>();
GroupBy groupBy = new GroupBy();
groupBy.initialDocument("vehicleTypeEnum");
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.NEISAN);
map.put("NEISAN", mongoOperations.find(query, Request.class));
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.BADSAN);
map.put("BADSAN", mongoOperations.find(query, Request.class));
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.BUJE);
map.put("BUJE", mongoOperations.find(query, Request.class));
content.setData(map);
return getReturn(content);
}
And this method apply criteria to each query
private void queryFieldsFilterLastFiveRequest(Query query, VehicleTypeEnum vehicleTypeEnum) {
query.addCriteria(Criteria.where("vehicleTypeEnum").is(vehicleTypeEnum));
query.addCriteria(Criteria.where("unlock").is(true));
query.fields()
.include("id")
.include("goodsTypeTitle")
.include("originCityTitle")
.include("price");
query.limit(5);
}
I wonder if there is any way to retrieve all list in one request to database using MongoOperations.
I would go to grouping manually later on, first query for all vehicleType :
private void queryFieldsFilterLastFiveRequest(Query query, VehicleTypeEnum... vehicleTypeEnum..) {
query.addCriteria(Criteria.where("vehicleTypeEnum").in(vehicleTypeEnum));
query.addCriteria(Criteria.where("unlock").is(true));
query.fields()
.include("id")
.include("goodsTypeTitle")
.include("originCityTitle")
.include("price");
query.limit(5);
}
Here the is has been changed by in, and accept a list of VehicleTypeEnum
Then to use it :
public ResponseEntity<?> getFiveLastRequestOfEachVehicleType() {
ResponseContent content = getResponseContent();
Map<String, List<Request>> map;
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.NEISAN, VehicleTypeEnum.BADSAN, VehicleTypeEnum.BUJE);
map = mongoOperations.find(query, Request.class).stream()
.collect(Collectors.toMap(r -> r.getVehicleTypeEnum().name(),r -> r));
content.setData(map);
return getReturn(content);
}
Here i use the stream api to group result by VehiculeTypeEnum name

How to use the QueryResult in Bluemix to get the BasicDocumentRevision

public List<Task> allTasks() {
int nDocs = this.mDatastore.getDocumentCount();
List<BasicDocumentRevision> all = this.mDatastore.getAllDocuments(0, nDocs, true);
List<Task> tasks = new ArrayList<Task>();
// Filter all documents down to those of type Task.
IndexManager im = new IndexManager(mDatastore);
List<Object> indexFields = new ArrayList<Object>();
indexFields.add("city");
indexFields.add("price");
indexFields.add("Area");
indexFields.add("Information");
indexFields.add("imagename");
// Create the index
im.ensureIndexed(indexFields);
Map<String, Object> query = new HashMap<String, Object>();
query.put("desc", "RESIDENTIAL PROPERTY");
QueryResult result = im.find(query);
for(BasicDocumentRevision rev :all) {
Task t = Task.fromRevision(rev);
if (t != null) {
tasks.add(t);
}
}
return tasks;
How do you use queryresult to get it stored in a task class object? I want my query to only be listed in listview. I am working on Bluemix, which uses Cloudant syn.
You can get the document revision from the QueryResult by iterating over the QueryResult Object like :
for(DocumentRevision rev : result){
Task t = Task.fromRevision(rev);
if(task != null)
tasks.add(t);
}

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 could i use JPA criteria query api for joined columns?

i am new to JPA and i have a problem with it.
suppose that we have two tables which are related
by a ManytoOne association, which means that
table A stores a primary key of table B within it.
when these two tables are mapped to JPA entities
i have a problem for search on this situation.
i have used an existing code from richfaces demo, to handle filtering and sorting by using
JPA. this code is using input parameters to create criteria query.
this is the code:
private CriteriaQuery<T> createSelectCriteriaQuery() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass);
Root<T> root = criteriaQuery.from(entityClass);
if (arrangeableState != null) {
List<Order> orders = createOrders(criteriaBuilder, root);
if (!orders.isEmpty()) {
criteriaQuery.orderBy(orders);
}
Expression<Boolean> filterCriteria = createFilterCriteria(criteriaBuilder, root);
if (filterCriteria != null) {
criteriaQuery.where(filterCriteria);
}
}
return criteriaQuery;
}
protected Expression<Boolean> createFilterCriteriaForField(String propertyName, Object filterValue, Root<T> root, CriteriaBuilder criteriaBuilder) {
String stringFilterValue = (String) filterValue;
if (Strings.isNullOrEmpty(stringFilterValue)) {
return null;
}
stringFilterValue = stringFilterValue.toLowerCase(arrangeableState.getLocale());
Path<String> expression = root.get(propertyName);
Expression<Integer> locator = criteriaBuilder.locate(criteriaBuilder.lower(expression), stringFilterValue, 1);
return criteriaBuilder.gt(locator, 0);
}
private Expression<Boolean> createFilterCriteria(CriteriaBuilder criteriaBuilder, Root<T> root) {
Expression<Boolean> filterCriteria = null;
List<FilterField> filterFields = arrangeableState.getFilterFields();
if (filterFields != null && !filterFields.isEmpty()) {
FacesContext facesContext = FacesContext.getCurrentInstance();
for (FilterField filterField : filterFields) {
String propertyName = (String) filterField.getFilterExpression().getValue(facesContext.getELContext());
Object filterValue = filterField.getFilterValue();
Expression<Boolean> predicate = createFilterCriteriaForField(propertyName, filterValue, root, criteriaBuilder);
if (predicate == null) {
continue;
}
if (filterCriteria == null) {
filterCriteria = predicate.as(Boolean.class);
} else {
filterCriteria = criteriaBuilder.and(filterCriteria, predicate.as(Boolean.class));
}
}
}
return filterCriteria;
}
the code is okay, when i try to filter columns(not joined columns), but when i try to
query on joined column, the produced query is not correct and it throws exception.
so my question is that, how could i use JPA criteria query api, to filter rows by both
joined columns and non-joined coulmns.
thanks
I don't believe you can treat join columns like regular ones.
for example if you want to filter on id of B, you would have to create a join from A to B , then use B_.id to match values.
Shay