How to update few fields in mongodb by using MongoRepository? - mongodb

I have a User POJO having fields:
#Id
private String _id;
private String phone;
private String email;
private String password;
private String userName;
private String dob;
private String gender;
private String city;
private String pincode;
private String status;
private String validUpto;
private List<String> userRole;
private String persona;
I saved all the fields in MongoDB (document).
Now I want to update only few fields like city, Pincode.
I also refer this question, but it is not giving the answer via MongoRepository.
is there any way we can update only few fields via MongoRepository instead of MongoTemplate.

The repository doesn't provide an 'update' operation only .save(object);
But you can update it by retrieving the Object from the repository, change the relevant fields. Afterwards, you save the updated object to the repository.
Which will get you the desired result of 'updating'.
Spring-boot/SpringRepository example.
#Autowired
UserRepository userRepository;
#Test
public void testUpdateUser() throws Exception {
User foundUser = userRepository.findById("1");
foundUser.setCity("Helsinki");
// foundUser.setOtherFields("new values");
userRepository.save(foundUser); // Will 'update' but it essentially replaces the entity in database
}

Related

Spring MongoDB: Auditing one-to-many relation subdocument

I am currently working on a self-taught project, thus I am a beginner in MongoDB and I am struggling to audit a subdocument in an one-to-many relation. For some reason none of the new records inserted in this collection is being audited, although audit is working fine for all the other collections.
Below is the structure of the collections in my project:
User document is the main Document - auditing ok
Provider is an embedded subdocument in User (One-to-One) - auditing ok
Address is an embedded set of documents in Provider (One-to-Many) auditing fail
public class User extends Audit<String>{
#Id
private String id;
private String email;
private String firstName;
private String lastName;
private String salt;
private String password;
private String role;
private Boolean isVerified;
private String userTempCode;
private LocalDateTime deactivationDate;
private Provider provider; // This subdocument gets audited no problem
...
public class Provider extends Audit<ObjectId>{
private ObjectId id = new ObjectId();
private LocalDate dob;
private String phone;
private Double price;
private Object geoLocation;
private Set<WeekDays> days;
private Set<TimeRange> hours;
private Set<Address> addresses; // Here is where I am having trouble, the createdBy, createdDate and so on, are not working
private String userId;
private LocalDateTime deactivationDate;
private Set<Reviews> ratings;
....
public class Address extends Audit<ObjectId>{
#Id
private ObjectId id = new ObjectId();
private String street;
private String street2;
private String city;
private String province;
private String country;
private String postalCode;
...
//Below My Audit class inherited by all documents
#Data
public abstract class Audit<T> implements Persistable<T> {
#CreatedBy
private String createdBy;
#CreatedDate
private LocalDateTime createdDate;
#LastModifiedBy
private String lastModifiedBy;
#LastModifiedDate
private LocalDateTime lastModifiedDate;
#Version
public Integer version;
}
So, why is my Set< Address> not being audited whereas the other documents are ok, am I missing something here?
Thank you!

Unable to override Auditable fields - createdAt

I've access_tokens collection and here is the corresponding class:
public class AccessToken extends Auditable {
#Id
private String id;
#NotBlank
private String token;
#DBRef
#NotBlank
private User user;
#NotBlank
private String origin;
public void setOrigin(String origin) {
this.origin = JwtUtils.getOrigin(origin);
}
#Indexed(expireAfter = "1d")
private LocalDateTime createdAt;
}
And here is the Auditable class:
public class Auditable {
#CreatedDate
private LocalDateTime createdAt;
#LastModifiedDate
private LocalDateTime updatedAt;
#CreatedBy
private ObjectId createdBy;
#LastModifiedBy
private ObjectId updatedBy;
}
The reason I'm defining createdAt in AccessToken is, I want to create a TTL index (basically I want to delete all access tokens after one day). But I'm getting following error:
Caused by: org.springframework.data.mapping.MappingException: Ambiguous field mapping detected! Both #org.springframework.data.annotation.CreatedDate()private java.time.LocalDateTime com.iof.models.Auditable.createdAt and private java.time.LocalDateTime com.iof.models.AccessToken.createdAt map to the same field name createdAt! Disambiguate using #Field annotation!
How can I solve this?

Spring data MongoDB match, lookup and projection to select only required field from looked-up document

I have below two Document structures. In the structure CRMContact.orgGroupId == OrganizationGroup.id. I would like to fetch all the CRMContact document that matches with sharedGroupIds and also select only a few fields from CRMContact and only OrganizationGroup.groupownername from OrganizationGroup and match/populate groupId (with only one field [groupownername] populated). I have used below custom implementation but didn't work.
I have included aggregarionsNotWorking which is not working and aggregarions returning entire OrganizationGroup populated. How to achieve this i.e. just to populate groupownername field, using spring data mongodb?
#Document(collection = "ww_crm_contact")
public class CRMContact{
#Id
protected String id;
private String displayName;
private String firstName;
private String middleName;
private String lastName;
private OrganizationGroup groupId; //Ignore //Modified field name orgGroupId
#Indexed(name = "CRMCONTACT_SHAREDGROUPID_IDX",background = true)
private List<String> sharedGroupIds = new LinkedList<>();
#Indexed(name = "CRMCONTACT_ORGGROUPID_IDX",background = true)
private String orgGroupId;
}
#Document(collection = "ww_organization_groups")
public class OrganizationGroup {
private static final long serialVersionUID = 600049975643062552L;
#Id
protected String id;
private String groupName;
private int riaId;
private Boolean isPrivate;
private String description;
private Boolean deleted;
#Transient
private int count;
private String groupownerid;
private String groupownername;
}
#Repository
public class CustomCRMContactDAO {
#Autowired
MongoTemplate mongoTemplate;
public List<CRMContact> getContactsPresentInGroup(List<ObjectId> objectIds){
LookupOperation lookupOperation = LookupOperation.newLookup().from("ww_organization_groups").localField("orgGroupId").foreignField("_id").as("groupId");
ProjectionOperation fields = project("firstName","lastName", "primaryId","displayName","groupId.groupownername");
Aggregation aggregarionsNotWorking = Aggregation.newAggregation(Aggregation.match(Criteria.where("sharedGroupIds").in(objectIds)),lookupOperation,unwind("groupId"),fields); //Not Working even if I change the field only to groupownername
Aggregation aggregarions = Aggregation.newAggregation(Aggregation.match(Criteria.where("sharedGroupIds").in(objectIds)),lookupOperation,fields); //
List<CRMContact> crmContacts = mongoTemplate.aggregate(aggregarions, "ww_crm_contact",CRMContact.class).getMappedResults();
return crmContacts;
}
}

Mapping POJOs and Using Reference in MongoDB using Morphia

I have two model classes. One is Company.java, another is HumanResource.java.
Company.java
#Entity("companies")
public class Company {
#Id
private ObjectId id = new ObjectId();
private String companyName;
private String emailAddress;
private String pictureUrl;
#Reference
private List<HumanResource> humanResources;
...
HumanResource.java
#Entity("humanresources")
public class HumanResource {
#Id
private ObjectId id = new ObjectId();
private String firstName;
private String lastName;
private String emailAddress;
#Reference
private Company company;
...
What I want to achieve is when I save a list of companies to datastore, related list of human resources documents should be inserted automatically.
In addition, I declared
#Id
private ObjectId id = new ObjectId();
in every model class. Is it a good way or should I change it ?
Morphia will not call save() on those references. You must call save() on the instances you want to persist. You can pass in a list of instances so you needn't loop, necessarily, but each instance needs to get passed in explicitly.

Spring Data JPA and QueryDSL - No property find found for type

I'm using Spring JPA 1.7 and QueryDSL 3.5.1. I am getting 'No property find found' error.
Here are my classes.
#Entity
#Table(name="Device")
public class Device implements Serializable {
private static final long serialVersionUID = 1L;
#NotEmpty
#Id
#Column(name="deviceId")
private String deviceId="";
#Column(name="accountId")
private String accountId="";
#Column(name="groupId")
private String groupId="";
#Column(name="equipmentType")
private String equipmentType="";
#Column(name="deviceCode")
private String deviceCode="";
#Column(name="deviceType")
private String deviceType="";
#NotEmpty
#Column(name="simId")
private String simId="";
#NotEmpty
#Column(name="imeiNumber")
private String imeiNumber="";
#Column(name="simPhoneNumber")
private String simPhoneNumber="";
#Column(name="driverId")
private String driverId="";
#Column(name="pushpinId")
private String pushpinId=""; //who registered device? JMA/MDM/JAMS
#Column(name="isActive", columnDefinition="INT(1)")
private boolean isActive = false;
#Column(name="displayName")
private String displayName="";
#Column(name="description")
private String description="";
#Column(name="notes")
private String notes="";
#Column
#JsonSerialize(using=DateSerializer.class)
private long creationTime;
#Column
#JsonSerialize(using=DateSerializer.class)
private long lastUpdateTime;
//Getters and setters
}
public interface DeviceRepository extends PagingAndSortingRepository<Device, String>, DeviceRepositoryCustom {
public Page<Device> findAll(com.mysema.query.types.Predicate predicate, Pageable pageable);
}
public interface DeviceRepositoryCustom {
public List<Device> selectByEquipmentTypeAndAnyColumnLike(String equipmentType, String creationTime, String searchField, String searchText, boolean hasPushId);
}
public class MdmPredicates {
public static com.mysema.query.types.Predicate anyFieldLike(String field, String text) {
QDevice device = QDevice.device;
//Do something later
return device.deviceId.contains(text);
}
}
Here is the error log:
aused by: org.springframework.data.mapping.PropertyReferenceException: No property find found for type entities.Device
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:75)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:271)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:245)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:72)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:188)
at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:277)
at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:257)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:68)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:57)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:90)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:290)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:158)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:162)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:44)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168)
I know that the error happens when I don't use real column name instead of property name. But the property names in the class are all same with column names.
Would you please tell me what I am I missing?
Your help would be appreciated.