How to create a composite index programmatically in spring Mongo data in Spring or spring boot? - spring

How to create a MongoDB composite index with Spring Data programmatically in Java?
Using MongoTemplate I can create an index like that:
mongoTemplate.indexOps("collectionName").ensureIndex(new Index().on("fieldName", Sort.Direction.DESC).
Is there a way to create a composite key?
I saw that there is the class CompoundIndexDefinition that, by its name seems to be doing that, but I could not get it to work.

You can create compound indexes on any collection using Spring Data programmatically in Java as below:
// Compound indexes on the fields: fieldOne & fieldTwo
// db.groups.createIndex({fieldOne:1, fieldTwo:1})
IndexDefinition index =
new CompoundIndexDefinition(new Document().append("fieldOne", 1).append("fieldTwo", 1));
mongoTemplate.indexOps(CollectionName.class).ensureIndex(index);
The above example will create same index as on mongo shell:
db.groups.createIndex({fieldOne:1, fieldTwo:1})

With Spring Data, you can create index programmatically using MongoTemplate or MongoOperations
mongoTemplate.indexOps(CollectionName.class)
.ensureIndex(new Index().on("fieldOne", Sort.Direction.DESC)
.on("fieldTwo", Sort.Direction.ASC));
mongoOperations.indexOps(CollectionName.class)
.ensureIndex(new Index().on("fieldOne", Sort.Direction.DESC)
.on("fieldTwo", Sort.Direction.ASC));

I think this is the more appropriate approach.
#CompoundIndexes({
#CompoundIndex(name = "customIndex", def = "{'fieldOne' : 1, 'fieldTwo': 1}")
})
public class Entity {}
In spring boot JPA Mongo repository.

Related

createIndex=true doesn't create the index mapping in Elasticsearch

createIndex=true doesn't create the index mapping in Elasticsearch using spring-data-elasticsearch
#Document(indexName = "profiles", shards=1, versionType = VersionType.INTERNAL, createIndex = true)
Setting the parameter createIndex = true (which by the way is the default value) by itself does not do anything.
You need to have a Spring Data Elasticsearch repository with the entity class that has this annotation in your application, and the index must not yet exist.
The check if the index exists is done on repository bootstrapping and only if the index does not exist, it will be created and the mappings are written to the index.

Convert ObjectId to String in Spring Data

How can I reference two mongodb collections using spring data while the localField is of type ObjectId and foreignField is of type String?
ProjectionOperation convertId=Aggregation.project().and("_id").as("agentId");
LookupOperation activityOperation = LookupOperation.newLookup().
from("activity").
localField("agentId").
foreignField("agent_id").
as("activities");
Aggregation aggregation = Aggregation.newAggregation(convertId,activityOperation);
return mongoTemplate.aggregate(aggregation, "agents", AgentDTO.class).getMappedResults()
However, this doesn't return any records because of the type issue. Is it possible to implement $toString or $convert in ProjectionOperation? or what other options are there?
I was able to solve it by writing native mongodb aggregation operation in java code as described in MongoDB $aggregate $push multiple fields in Java Spring Data
After implementing this solution I was able to add native $addfields as follows:
AggregationOperation addField=new GenericAggregationOperation("$addFields","{ \"agId\": { \"$toString\": \"$_id\" }}");

How to get top results using specifications in spring data jpa?

I am quite new to spring data jpa. I am trying to use specifications while querying database. My question is using crudrepository we can method like :
findTopByUsernameOrderByUpdatedAtDesc(String username);
How can I achieve the same using specifications? I can do basic things like and or in specifications, but not very robust like we can do with criteria etc.
Specification<CustomClass> spec = Specifications.where(specification).and(username);
List<CustomClass> list = findAll(spec);
This was done as follows :
Pageable pageable = new PageRequest(0, 1, Sort.Direction.DESC, "username");
Page oneElementPage = repository.findAll(spec, pageable);
This will sort the data on username column in descending direction and return first result.
You can't express this in a Specification directly. But you can use a Pageable for this:
Page oneElementPage = repository.findAll(spec, new PageRequest(0, 1));
Gives you a Page with a single element.

How to make a custom sorting query in spring boot for a mongo db repository?

I want to put this query with #Query annotation in my repository.
This is the query:
`db.report.find({'company' : 'Random'}).sort( { 'reportDate' : -1} ).limit(1)`
Which is the best way to implement custom queries with #Query annotations or to use MongoTemplate ?
Using Mongo Template.
Criteria find = Criteria.where("company").is("Random");
Query query = new Query().addCriteria(find).with(new Sort(Sort.Direction.DESC, "reportDate"));
BasicDBObject result = mongoOperations.findOne(query, BasicDBObject.class, "collection_name");
Using Mongo Repository
Report findTopByCompanyOrderByReportDateDesc(String company)
Note that in the new version of Springboot(v2.2.5), the correct method is sort.by().
like this:
Query query = new Query().addCriteria(find).with(Sort.by(Sort.Direction.DESC, "reportDate"));

Group toghether Node properties and return as a view in Cypher

I am working with v2.2.3 of Neo4J and Spring Neo4j Data SDN 4
I want to return a few properties of a node using a cypher query and map them into attributes of a POJO.My function in Spring data repository looks something like this
#Query(
"MATCH(n:ServiceProvider{profileStatus:{pStatus},currentResidenceState:{location}}) RETURN n.name,n.currentResidenceAddress ,n.employmentStatus,"
+ "n.idProofType,n.idProofNumber
ORDER BY n.registrationDate DESC SKIP{skip} LIMIT {limit}")
List<AdminSearchMapResult> getServiceProviderRecords(
#Param("pStatus")String pStatus,
#Param("location")String location,
#Param("skip") int skip,#Param("limit")int limit);
I get an error like
Scalar response queries must only return one column. Make sure your cypher query only returns one item.
I think its because of the fact that I cant bundle all the returned attributes into a view that can map into the POJO
If I return the node itself and map it into a POJO it works
Kindly guide
This can be done using #QueryResult
Annotate the AdminSearchMapResult POJO with #QueryResult. For example:
#QueryResult
public class AdminSearchMapResult {
String name;
String currentResidenceAddress;
...
}
Optionally annotate properties with #Property(name = "n.idProofType") if the alias is different from the field name.

Resources