Spring data mongoDB: Get the distinct rows with pagination - spring

I have User class like,
#Document(collection = "users")
public class User {
private String id;
private String firstName;
private String lastName;
private String jobTitle;
private String email;
private String phoneNumber;
}
And UserDimension as,
#Document(collection = "userDimensions")
public class UserDimension{
private String id;
private String userId;
private String dimensionId;
private String status;
}
I want the userDimension records from mongoDB based on distinct userId with pagination in spring data mongoDB ?
I am using the query like,
Query query = new Query();
List<UserDimension> userDimensionList = null;
// apply pagination parameters to the search criteria
query.with(pageable);
userDimensionList = mongoTemplate.getCollection("userDimensions").distinct("userId", query.getQueryObject());
But it still giving me the total records.

Related

Spring MongoDB Query Criteria by keys of Map

I have document
public class Person {
private String id;
private String email;
private String firstName;
private String lastName;
private Map<String, Boolean> hobbies;
}
And have request with Set of reqHobbies. I need to find persons from my collection with hobbies of set.
I find a solution like
query.addCriteria(Criteria.where("hobbies").all(reqHobbies)); - this work, if my hobbies is List/Set.
Thanks for the help!

Sprint error querying embedded documents in mongoDB

I have a
#Data
#Document(collection = "req_language")
public class Language implements ChangeDto {
#Id
private String id = UUID.randomUUID().toString();
private String name;
private String code;
private Boolean active = Boolean.TRUE;
private Boolean deleted = Boolean.FALSE;
private Date changeAt = Date.from(Instant.now());
private String changedBy;
private String correlationId = UUID.randomUUID().toString();
}
And
#Data
#Document(collection = "req_locale")
public class Locale implements ChangeDto {
#Id
private String id = UUID.randomUUID().toString();
private String description;
private Language language;
private String code;
private String fatherCode;
private Boolean active = Boolean.TRUE;
private Boolean deleted = Boolean.FALSE;
private Date changedAt = Date.from(Instant.now());
private String changedBy;
private String correlationId = UUID.randomUUID().toString();
}
With a simple repository
#Repository
#JaversSpringDataAuditable
public interface LocalesRepository extends MongoRepository<Locale, String>, LocalesCustom {
List<Locale> findByCode(String code);
}
If a try to use the findByCode, I receive this error:
No converter found capable of converting from type [java.lang.String] to type [XXX.Language]
When I try to use query in the LocalesCustom, for example (empty)
Query query = new Query();
List<Locale> localeList = mongoTemplate.find(query, Locale.class);
Same error
I have tried #DBRef in Language, and popped others errors (I couldn't query by the language code, query.addCriteria(Criteria.where("language.code")) in LocalesRepository.
There's a right way to do it?

Springboot query criteria : mongodb

I have list of filtered Id as following:
filteredId=[5,44,221,34,111...]
and class Device.java:
#NotBlank
private String applicationId;
// #NotBlank
private String deviceTypeId;
#NotBlank
private String uid;
#NotBlank
private String name;
private String userId;
private String nodeId;
private String externalId;
private String softwareReleaseId;
private boolean enabled = CoreConstant.DEFAULT_ENABLED;
private boolean nameOverridden = KronosConstants.NAME_OVERRIDDEN_DEFAULT;
private Map<String, String> info = new HashMap<>();
//Getter Setter
I want to fetch all Devices which have deviceTypeId equals filteredId
I am doing something like this:
Query query = new Query();
for (int i = 0; i < filteredId.size(); i++) {
query.addCriteria(Criteria.where(filteredId.get(i)).is(device.getId()));
}
return this.MongoOperations.find(query, Device.class);
Can anyone help me with what changes I need?
try
List<Integer> filteredId = List.of(5,44,221,34,111);
Criteria criteria = Criteria.where("deviceTypeId").in(filteredId);
return mongoOperations.find(Query.query(criteria), Device.class);

Project embedded document fields after lookup operation

I want to do a join between Timesheet:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Document(collection = TIMESHEET_COLLECTION)
public class Timesheet {
#Id
private ObjectId id;
private ObjectId employeeId;
private LocalDate date;
private String occupationTitle;
private BigDecimal salary;
private List<TimesheetEntry> entries;
}
and Employee (as embedded document):
#Data
#AllArgsConstructor
#NoArgsConstructor
#Document(collection = Employee.EMPLOYEE_COL)
public class Employee {
#Id
private ObjectId id;
private String registry;
private String cpf;
private String firstName;
private String lastName;
private String nickname;
private String phone;
private LocalDate dateOfBirth;
private LocalDate admissionDate;
private EmployeeOccupation occupation;
private EmployeePaymentPreferences paymentPreferences;
private Map<String, String> equipmentPreferences;
private Boolean active;
}
So I have this aggregation query, with match, lookup, unwind and projection operations.
Aggregation aggregation = Aggregation.newAggregation(matchTimesheetFilter(timesheetFilter), lookupEmployee(), unwindEmployee(), projectEmployee());
There are lookup and unwind implementations. I'm unwinding because employee should be a single object, not an array.
private LookupOperation lookupEmployee(){
return LookupOperation.newLookup()
.from("employee")
.localField("employeeId")
.foreignField("_id")
.as("employee");
}
private UnwindOperation unwindEmployee(){
return Aggregation.unwind("employee");
}
It returns successfully a Timesheet document with a embedded Employee document. The point is: I don't want all data from employee. I only want a few fields.
So, I tried to exclude unwanted fields from employee, using my projection operation:
private ProjectionOperation projectEmployee() {
return Aggregation.project().andExclude("employee.nickname", "employee.firstName", "employee.fullName");
}
It didn't work. My embedded employee is still being returned with all fields. However I can successfully exclude fields from Timesheet, if I do something like this:
private ProjectionOperation projectEmployee() {
return Aggregation.project().andExclude("startDate", "endDate");
}
How can I project custom fields from a document embedded through a lookup operation?
i think you need to exclude "employee.nickname", "employee.firstName", "employee.fullName", instead of "nickname", "firstName", "fullName"
Try this:
private ProjectionOperation projectEmployee() {
return Aggregation.project().andExclude("employee.nickname", "employee.firstName", "employee.fullName");
}
i did it this way (not sure if it's right but it works):
private LookupOperation lookupEmployee(){
return LookupOperation.newLookup()
.from("employee")
.localField("employeeId")
.foreignField("_id")
.as("employeeLookup");
}
no unwind used
Aggregation.project().and("employeeLookup.firstName").as("employee.firstName")

How to search nested object by using Spring Data Solr?

I have two such Java object:
public class PSubject
{
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("name")
private String name;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("type")
private String type;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("uri")
private String uri;
#OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
#IndexedEmbedded
#org.apache.solr.client.solrj.beans.Field("attributes")
private Set<PAttribute> attributes = new HashSet<PAttribute>();
.....
}
#Entity
#Indexed
#Table(name="PAttribute")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class PAttribute extends PEntity
{
private static final long serialVersionUID = 1L;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.YES)
#org.apache.solr.client.solrj.beans.Field("attr_name")
private String name;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.YES)
#org.apache.solr.client.solrj.beans.Field("attr_value")
private String value;
.....
}
And my Spring Data Solr query interface:
public interface DerivedSubjectRepository extends SolrCrudRepository<PSubject, String> {
Page<PSubject> findByName(String name, Pageable page);
List<PSubject> findByNameStartingWith(String name);
Page<PSubject> findBy(Pageable page);
#Query("name:*?0* or description:*?0* or type:*?0* or mac_address:*?0* or uri:*?0* or attributes:*?0*")
Page<PSubject> find(String keyword,Pageable page);
#Query("name:*?0* or description:*?0* or type:*?0* or mac_address:*?0* or uri:*?0* or attributes:*?0*")
List<PSubject> find(String keyword);
}
I can search any by name, description, type and mac_address, but can't search any result by attribute.
Update:
For example,when user search "ipod", it's probably means the type of subject or name of subject, or the name of attribute or the value of attribute. And I want get all the matched subject in one request. I know I can search the attribute object in a separate query. But that makes the code in the backend complex.
So, how can I search this nested object?
Update:
I flattened my data:
#Transient
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("attrs")
private String attrs;
public String getAttrs() {
return attrs;
}
public void setAttrs(Set<PAttribute> attributes) {
StringBuffer attrs = new StringBuffer();
if(attributes==null) {
attributes = this.getAttributes();
}
for(PAttribute attr:attributes){
attrs.append(attr.getName()+" " + attr.getValue()).append(" ");
}
this.attrs =attrs.toString();
}
The issue is resolved.
IIRC it is not possible to store nested data structures in solr - it depends how you flatten your data to fit into an eg. multivalue field - a little hard not knowing your schema.
see: http://lucene.472066.n3.nabble.com/Possible-to-have-Solr-documents-with-deeply-nested-data-structures-i-e-hashes-within-hashes-td4004285.html
How does the data look like in you index, and did you have a look at the http request sent by spring-data-solr?

Resources