Foreign Key/DBRef in Spring Data Firestore - spring

I have 2 entities:
1- User:
#Document(collectionName = CollectionConstants.USER_COLLECTION)
public class User {
#DocumentId
protected String id;
private String username;
}
2- Contest:
#Document(collectionName = CollectionConstants.CONTEST_COLLECTION)
public class Contest {
private List<User> contestants;
}
How can I save only the ID of the user (whether it's a list of users, or a single user) in the database while letting Spring Data manage that automatically?
I'm actually looking for an alternative for the following:
Spring Data JPA: #OneToMany, #ManyToOne
Spring Data MongoDB: #DBRef

I have checked in the Spring Cloud GCP for Firestore, and it states:
The starter automatically configures and registers a Firestore bean in the Spring application context. To start using it, simply use the #Autowired annotation.
#Autowired
Firestore firestore;
void writeDocumentFromObject() throws ExecutionException, InterruptedException {
// Add document data with id "joe" using a custom User class
User data = new User("Joe",
Arrays.asList(
new Phone(12345, PhoneType.CELL),
new Phone(54321, PhoneType.WORK)));
// .get() blocks on response
WriteResult writeResult = this.firestore.document("users/joe").set(data).get();
LOGGER.info("Update time: " + writeResult.getUpdateTime());
}
User readDocumentToObject() throws ExecutionException, InterruptedException {
ApiFuture<DocumentSnapshot> documentFuture =
this.firestore.document("users/joe").get();
User user = documentFuture.get().toObject(User.class);
LOGGER.info("read: " + user);
return user;
}
There is sample https://github.com/spring-cloud-gcp/spring-cloud-gcp-samples/spring-cloud-gcp-firestore-sample

Related

Spring data mongo db not creating some collections

I am using spring boot starter 2.1.6 and spring-data-mongo starter version is 2.1.6.RELEASE.
Whenever the server starts i understood spring boot mongo creates the collection schema. For some reason spring boot mongo does not create collection schema for some specific collection. These collections are all the time same ones.
But when i create programatically by myself they are created without error or warning.
mongoTemplate.createCollection("collectionName");
I would like to know how to find out why spring boot is not able to
create these specific collections.
For example below is one of the collection which is not created automatically by spring boot.
#Document(collection = "subscription_histories")
public class SubscriptionHistoryModel extends AbstractModel {
private static final long serialVersionUID = 4424861457985412905L;
#NotNull
#DBRef(lazy = true)
#Field("customer")
private CustomerModel customer;
#NotNull
#Field("subscription_from")
private Instant subscriptionFrom;
#NotNull
#Field("subscription_to")
private Instant subscriptionTo;
public CustomerModel getCustomer() {
return customer;
}
public void setCustomer(CustomerModel customer) {
this.customer = customer;
}
public Instant getSubscriptionFrom() {
return subscriptionFrom;
}
public void setSubscriptionFrom(Instant subscriptionFrom) {
this.subscriptionFrom = subscriptionFrom;
}
public Instant getSubscriptionTo() {
return subscriptionTo;
}
public void setSubscriptionTo(Instant subscriptionTo) {
this.subscriptionTo = subscriptionTo;
}
#Override
public int hashCode() {
return super.hashCode();
}
#Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
I've been struggling on this issue for past 2 days as well. Finally found why was this happening.
So if you're using docker for the mongodb and mongodb express. Idk for some reason the data is being stored locally and accessed from there and not the mongodb docker container. I've also installed mongodb locally and was trying to run using docker as well.
So, you must check if there are any other places where your mongodb service might be running and your program might be referring to that place!

Spring Data REST - prevent property edit based on role

I use Spring Boot with Spring Data REST for data access and Spring Security for access restriction.
Assume I've got simple entity:
#Entity
public class Person {
#Id #GeneratedValue
private Long id;
private String firstName;
private Boolean isAuthorizedForClasifiedData;
}
I've got two roles in the application: USER and ADMIN.
Is there any simple way to prevent USER from changing value of isAuthorizedForClasifiedData while allowing ADMIN to update it?
The only solution I came up with is writing your own setter method.
public void setIsAuthorizedForClasifiedData(Boolean isAuthorizedForClasifiedData) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Optional<? extends GrantedAuthority> role_admin = authentication.getAuthorities().stream().filter(role -> role.getAuthority().equals("ROLE_ADMIN")).findAny();
role_admin.orElseThrow(() -> new YourOwnForbiddenException());
this.test = test;
}

auditing filelds in spring data

I'm beginner in java programming. And I try to write simple stand alone application with spring data. To basic example which is here http://spring.io/guides/gs/accessing-data-jpa/ I want to add, auditing mechanism which will store previous values for objects. I want in customer entity, on #PreUpdate store old values in another table, but I do not know how.
#Entity
#EntityListeners(AuditingEntityListener.class)
public class Customer implements Serializable {
...
#Transient
private transient Customer savedState;
#PreUpdate
public void onPreUpdate() {
if (!savedState.firstName.equals(this.firstName)) {
log.info(String.format("first name was modified, new value =%s, old value=%s",this.firstName, savedState.firstName ));
}
}
#PostLoad
private void saveState(){
this.savedState = (Customer) SerializationUtils.clone(this); // from apache commons-lang
}

Externalize mongo json query using spring boot

I have just started using spring data MongoDb with Spring-Boot.
I have some mongo based json queries added in the interface using #query annotation when using spring data repository.
I want to know if it is possible to externalize or separate out the JSON query outside the codebase so that it can be optimized separately and
also not having it mixed with code.
Thanks for your suggestions.
This is the code which i have added in my interface and annotated with #query annotation.
#Query("{ 'firstname' : ?0 ,'lastname': ?1}")
List findByCriteria(String firstname,String lastname);
The above is a simple example. I have complex conditions involving $and and $or operators too .
What i basically want to achieve is externalize the above native mongo json query to a config file and refer that in the above annotation.
Spring data supports something similar when using jpa with hibernate. But not sure if we can do the same using spring data mongodb with spring boot.
Do like this (I am explaining only for the API)
Suppose you have an Entity user
At the Top there will be User domain
public class User extends CoreDomain {
private static final long serialVersionUID = -4292195532570879677L;
#Length(min = 2)
private String name;
#Length(min = 2)
#UniqueUserName(message = "User name already registered,Please choose something Different")
private String userName;
#Length(min = 6)
private String password;
}
User Controller
User Service (Interface)
User ServiceImpl(Service Implementation)
Mongo Repository(Since, I have MongoDb)
Now in userController you will take all the queries , Param(Parameters) , Pagerequest like this
public class UserController extends CoreController {
#Autowired
private UserService userService;
/*
* This controller is for getting the UserDetails on passing the UserId in
* the #param Annotation
*/
#GET
#Path("{id}")
public User getUser(#PathParam("id") String UserId) {
User user = new User();
user = userService.findUserId(UserId);
if (user == null)
throw new NotFoundException();
log.info("The userId you searched is having the details as :" + user);
return user;
}}
For serviceInterface you will have :
public interface UserService {
// Boolean authenticateUser(User user);
User findUserId(String UserId);
}
For serviceImpl :
public class UserServiceImpl implements UserService {
#Setter
#Autowired
private UserRepository userRepository;
/*
* This method will find user on the basis of their userIds passed in the
* parameter.
*/
#Override
public User findUserId(String UserId) {
User userIdResult = userRepository.findOne(UserId);
log.info("The userDetail is" + userIdResult);
return userIdResult;
}
In mongoRepository for user we will have:
A default query findById(String userId);
Hopefully this will help you.

QueryDsl MongoDb Relation

I am trying to use Mongodb with spring-data and QueryDsl.
I have following entitys:
#QueryEntity
#Document(collection="groups")
public class GroupImpl implements Group {
private String name;
#DBref
private List<User> groupMembers;
and
#QueryEntity
#Document(collection="users")
public class UserImpl implements User{
public static final String FIRST_NAME = "firstName";
public static final String LAST_NAME = "lastName";
My Repositories are implemented like this:
public interface GroupRepository extends Repository<Group, String>,QueryDslPredicateExecutor<Group>{}
Every normal CRUD operations were running successfully.
Also operations like "getUserByEmail" etc working successfully.
Now I am trying to get all Groups of an User in a UnitTest.
#Before
public void setup(){
roles = Arrays.asList(new String[]{"admin","user","guest"});
user = new UserImpl();
user.setFirstName("Foo");
user.setLastName("Bar");
user.setShortname("fbar");
user.setEMail("foo#bar.com");
user.setRoles(roles);
user2 = new UserImpl();
user2.setFirstName("Foo");
user2.setLastName("Bar");
user2.setShortname("fbar");
user2.setEMail("foo#bar.com");
user2.setRoles(roles);
user = userRepository.save(user);
user2 = userRepository.save(user2);
group = new GroupImpl();
group.setGroupMembers(Arrays.asList(new User[]{user,user2}));
group.setName("testGroup2");
group2 = new GroupImpl();
group2.setGroupMembers(Arrays.asList(new User[]{user,user2}));
group2.setName("testGroup2");
}
#Test
public void findGroupsByUser(){
Group savedGroup = repository.save(group);
Group savedGroup2 = repository.save(group2);
Assert.assertTrue(savedGroup2.getGroupMembers().contains(user));
List<Group> foundGroup = (List<Group>)repository.findAll(QGroupImpl.groupImpl.groupMembers.contains(user));
Assert.assertNotNull(foundGroup);
Assert.assertEquals(2, foundGroup.size());
}
This test fails "expected:<2> but was:<0>"
I am confused because savedGroup2 contains the user but if I try to get all Groups with this groupmember using QueryDsl I get no result.
I already checked the database and the users are stored successfully.
I also debugged and checked if the "_id"s of the given user and the user in the database are equal.
I have no Idea whats wrong.

Resources