How to specify the table name in hibernate criteria Projections.sqlGroupProjection - group-by

I want to use group by to field called "created_on" in hibernate criteria. I have joined 2 tables and both tables are having "created_on" field. How can I specify the field name with table name in sqlGroupProjection in hibernate criteria.
Criteria criteria = getSession().createCriteria(Receipt.class, "rec");
criteria.createAlias("rec.Invoice", "inv", JoinType.LEFT_OUTER_JOIN);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.sqlGroupProjection("date(created_on) as createdOn", "createdOn", new String[] { "createdOn" }, new Type[] { StandardBasicTypes.DATE }));
criteria.setProjection(proList);

you have to use the alias {alias} , your code will be :
Criteria criteria = getSession().createCriteria(Receipt.class, "rec");
criteria.createAlias("rec.Invoice", "inv", JoinType.LEFT_OUTER_JOIN);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.sqlGroupProjection("date({alias}.created_on) as createdOn", "createdOn", new String[] { "createdOn" }, new Type[] { StandardBasicTypes.DATE }));
criteria.setProjection(proList);

Related

How to compare two collections and archive documents which are not common

I have two collections for example CollectionA and CollectionB both have common filed which is hostname
Collection A :
{
"hostname": "vm01",
"id": "1",
"status": "online",
}
Collection B
{
"hostname": "vm01",
"id": "string",
"installedversion": "string",
}
{
"hostname": "vm02",
"id": "string",
"installedversion": "string",
}
what i want to achieve is when i receive a post message for collection B
I want to check if the record exists in Collection B based on hostname and update all the values. if not insert the new record ( i have read it can be achieved by using upsert -- still looking how to make it work)
I want to check if the hostname is present in Collection A , if not move the record from collection B to another collection which is collection C ( as archive records).ie in the above hostname=vm02 record from collection B should be moved to collectionC
how can i achieve this using springboot mongodb anyhelp is appreciated.The code which i have to save the Collection B is as follows which i want to update to achieve the above desired result
public RscInstalltionStatusDTO save(RscInstalltionStatusDTO rscInstalltionStatusDTO) {
log.debug("Request to save RscInstalltionStatus : {}", rscInstalltionStatusDTO);
RscInstalltionStatus rscInstalltionStatus = rscInstalltionStatusMapper.toEntity(rscInstalltionStatusDTO);
rscInstalltionStatus = rscInstalltionStatusRepository.save(rscInstalltionStatus);
return rscInstalltionStatusMapper.toDto(rscInstalltionStatus);
}
Update 1 : The below works as i expected but I think there should be a better way to do this.
public RscInstalltionStatusDTO save(RscInstalltionStatusDTO rscInstalltionStatusDTO) {
log.debug("Request to save RscInstalltionStatus : {}", rscInstalltionStatusDTO);
RscInstalltionStatus rscInstalltionStatus = rscInstalltionStatusMapper.toEntity(rscInstalltionStatusDTO);
System.out.print(rscInstalltionStatus.getHostname());
Query query = new Query(Criteria.where("hostname").is(rscInstalltionStatus.getHostname()));
Update update = new Update();
update.set("configdownload",rscInstalltionStatus.getConfigdownload());
update.set("rscpkgdownload",rscInstalltionStatus.getRscpkgdownload());
update.set("configextraction",rscInstalltionStatus.getConfigextraction());
update.set("rscpkgextraction",rscInstalltionStatus.getRscpkgextraction());
update.set("rscstartup",rscInstalltionStatus.getRscstartup());
update.set("installedversion",rscInstalltionStatus.getInstalledversion());
mongoTemplate.upsert(query, update,RscInstalltionStatus.class);
rscInstalltionStatus = rscInstalltionStatusRepository.findByHostname(rscInstalltionStatus.getHostname());
return rscInstalltionStatusMapper.toDto(rscInstalltionStatus);
}
Update2 : with the below code i am able to get move the records to another collection
String query = "{$lookup:{ from: \"vmdetails\",let: {rschostname: \"$hostname\"},pipeline:[{$match:{$expr:{$ne :[\"$hostname\",\"$$rschostname\"]}}}],as: \"rscInstall\"}},{$unwind:\"$rscInstall\"},{$project:{\"_id\":0,\"rscInstall\":0}}";
AggregationOperation rscInstalltionStatusTypedAggregation = new CustomProjectAggregationOperation(query);
LookupOperation lookupOperation = LookupOperation.newLookup().from("vmdetails").localField("hostname").foreignField("hostname").as("rscInstall");
UnwindOperation unwindOperation = Aggregation.unwind("$rscInstall");
ProjectionOperation projectionOperation = Aggregation.project("_id","rscInstall").andExclude("_id","rscInstall");
OutOperation outOperation = Aggregation.out("RscInstallArchive");
Aggregation aggregation = Aggregation.newAggregation(rscInstalltionStatusTypedAggregation,unwindOperation,projectionOperation,outOperation);
List<BasicDBObject> results = mongoTemplate.aggregate(aggregation,"rsc_installtion_status",BasicDBObject.class).getMappedResults();
this issue which i have here is it returns multiple records
Found the solution , there may be other best solutions but for me this one worked
create a class customeAggregationGeneration (found in SO answers and extended to match my needs)
public class CustomProjectAggregationOperation implements AggregationOperation {
private String jsonOperation;
public CustomProjectAggregationOperation(String jsonOperation) {
this.jsonOperation = jsonOperation;
}
#Override
public Document toDocument(AggregationOperationContext aggregationOperationContext) {
return aggregationOperationContext.getMappedObject(Document.parse(jsonOperation));
}
}
String lookupquery = "{$lookup :{from:\"vmdetails\",localField:\"hostname\",foreignField:\"hostname\"as:\"rscinstall\"}}";
String matchquery = "{ $match: { \"rscinstall\": { $eq: [] } }}";
String projectquery = "{$project:{\"rscinstall\":0}}";
AggregationOperation lookupOpertaion = new CustomProjectAggregationOperation(lookupquery);
AggregationOperation matchOperation = new CustomProjectAggregationOperation(matchquery);
AggregationOperation projectOperation = new CustomProjectAggregationOperation(projectquery);
Aggregation aggregation = Aggregation.newAggregation(lookupOpertaion, matchOperation, projectOperation);
ArrayList<Document> results1 = (ArrayList<Document>) mongoTemplate.aggregate(aggregation, "rsc_installtion_status", Document.class).getRawResults().get("result");
// System.out.println(results1);
for (Document doc : results1) {
// System.out.print(doc.get("_id").toString());
mongoTemplate.insert(doc, "RscInstallArchive");
delete(doc.get("_id").toString());

Grails 3 saving mongoDB document with both _id and id

We noticed an issue after an upgrade to grails 3 that we were saving mongoDB documents with both _id and id. (example document below)
How do we stop the saving of id? This happens for every collection the application creates and updates documents for.
{
"_id" : ObjectId("5b0ed1b710b3641a98aaee63"),
"value" : "testing",
"type" : "testingCreate",
"updateDate" : ISODate("2018-05-30T16:30:39.987Z"),
"updateUser" : "TSTUSR",
"id" : ObjectId("5b0ed1b710b3641a98aaee63")
}
The save is being called from the following
def test = new AppParam(type: "testingCreate",
updateUser: "TSTUSR",
updateDate: new Date(),
value: "testing")
test.save(failOnError:true, flush:true)
for the appParam domain of
class AppParam {
ObjectId id
String type
String value
String updateUser
Date updateDate
static mapWith = "mongo"
static mapping = {
version false
writeConcern WriteConcern.ACKNOWLEDGED
}
static constraints = {
type size: 1..50, matches:/^[^<>]{1,50}$/, validator: { field, obj ->
if (!field.trim()) return ['typeRequired']
return true
}
value size: 1..2000, matches:/^[^<>]{1,2000}$/, validator: { field, obj ->
if (!field.trim()) return ['valueRequired']
return true
}
}
}
We are using grailsVersion 3.2.11 and gormVersion 6.1.7.RELEASE
Try the following in the mapping closure.
static mapping {
id column: '_id'
version false
writeConcern WriteConcern.ACKNOWLEDGED
}
Did a bit more research into Mike W's comment after Grails 3.X it should be defaulting the mongodb engine to codec and we were manually defaulting the mongodb.engine = "mapping".

how to customize return table snapshot by hibernate en verse query

i am try with hibernate enverse below example code.
List personsAtAddress = getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true)
getting the out put as jsen format as below
[ {"id"=1,
"name" ="ssss"
},{
"revid" =1,
"username" ="kkk"
},
MOD
]
but my expected output is
["my entity" {"id"=1,
"name" ="ssss"
},
"custom Revision Tale"{
"revid" =1,
"username" ="kkk"
},
"modflag"="MOD"
]
how to get this result by a audit query in hibernate enverse
You basically need to marshal the returned Object[] array from the Envers API to a Map using the keys your output expects to get the results.
final List<Map<String,Object> output = new ArrayList<>();
final List<Object[]> results = // this is the list of object arrays from Envers
for ( Object[] row : results ) {
final Map<String, Object> map = new HashMap<>();
map.put( "my entity", row[0] );
map.put( "custom Revision Tale", row[1] );
map.put( "modflag", row[2] );
output.add( map );
}

How to write multiple group by id fields in Mongodb java driver

In the below query
{ $group : {
_id : { success:'$success', responseCode:'$responseCode', label:'$label'},
max_timeStamp : { $timeStamp : 1 },
count_responseCode : { $sum : 1 },
avg_value : { $sum : "$value" },
count_success : { $sum : 1 }
}}
How _id : { success:'$success', responseCode:'$responseCode', label:'$label'}, can be translated to use in java mongodb driver.
I tried
BasicDBList list = new BasicDBList();
list.add(new BasicDBObject("success", "$success"));
list.add(new BasicDBObject("responseCode", "$responseCode"));
list.add(new BasicDBObject("label", "$label"));
AggregationOutput output = collection.aggregate(match, project, group);
and
Multi-dimension array
String [][] muitiGroupBy = {{"success", "$success"},{"responseCode", "$responseCode"},{"label", "$label"}};
etc..
But i always get like this as result
"_id" : [ { "success" : "$success"} , { "responseCode" : "$responseCode"}]
If I use only one field it works.
DBObject groupFields = new BasicDBObject( "_id", new BasicDBObject("success", "$success"));
I had a similar need and titogeo's answer from 2013 led me in the right direction after many failed attempts to translate my aggregation operation into something the Java client could handle. This is what I used:
MongoCollection<Document> myCollection = myDB.getCollection("myCollection");
Map<String, Object> multiIdMap = new HashMap<String, Object>();
multiIdMap.put("groupField1", "$groupField1");
multiIdMap.put("groupField2", "$groupField2");
Document groupFields = new Document(multiIdMap);
AggregateIterable<Document> aggregate = myCollection.aggregate(Arrays.asList(
Aggregates.group(groupFields,
Accumulators.last("lastDate", "$dateCreated"),
Accumulators.last("lastNumAvail", "$availableUnits")
)
));
I got back exactly what I needed to match the result from this:
db.myCollection.aggregate([
{"$group":{ "_id":{
groupField1: "$groupField1",
groupField2: "$groupField2"},
lastDate:
{"$last":"$dateCreated"},
lastNumAvail:
{"$last":"$availableUnits"}
}
}
]);
We did figure out how. We can achieve by using this.
Map<String, Object> dbObjIdMap = new HashMap<String, Object>();
dbObjIdMap.put("success", "$success");
dbObjIdMap.put("responseCode", "$responseCode");
dbObjIdMap.put("label", "$label");
DBObject groupFields = new BasicDBObject( "_id", new BasicDBObject(dbObjIdMap));
I could achieve this through this code (grails code and mongo-java-driver-3.2):
DBObject groupFields = new BasicDBObject()
groupFields.put('success', "\$success")
groupFields.put('responseCode', "\$responseCode")
groupFields.put('label', "\$label")
def result = collection.aggregate(Arrays.asList(Aggregates.group(groupFields, []))).iterator()

Lucene 'join' how-to? part II

Part I here...
Requirement:
search by multiple values in multiple fields AND Where Bar.Id == argBar.Id
var parser = new MultiFieldQueryParser
(new[] { "Name", "Title" }, new SimpleAnalyzer());
parser.???(string.Format("Bar.Id:{0}",argBar.Id)); // o_0
var query = Session.CreateFullTextQuery
(parser.Parse(searchValue), new[] { typeof(Foo) });
Found this:
Query searchQuery = MultiFieldQueryParser.Parse
(term, new[] {"title", "description"},
new[] {BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD},
new StandardAnalyzer());
So, theoretically - i should be able to add argBar.Id and BooleanClause.Occur.Must, but there isn't such an overload in Lucene.Net 2.4.0.2.
var bq = new BooleanQuery();
bq.Add(parser.Parse(searchValue), BooleanClause.Occur.SHOULD);
bq.Add(new TermQuery
(new Term("Bar.Id", argBar.Id.ToString()), BooleanClause.Occur.Must);
var r = Session.CreateFullTextQuery(bq, new[] {typeof(Foo)});
//victory