how should i get data from mongo db using spring mongo repository? - spring

i am using mongodb in my spring boot application and i am using mongo repository interface to get data from the database this is the way i am getting the data .
School sch=repository.findOne("id");
this will give me the school object then i can get all the data from there but my question is will it affect my application's performance if i get the whole object everytime i need some data from that object even if i need some fields . if so what will be the method to do that i searched and i see that using Query annotiation i can limit the fields but even then it give whole object it put all the other fields null and data is only at fields which i specify . any guidence will be helpfull .

You can use a projection interface to retrieve a subset of attributes.
Spring Data Mongo DB
interface NamesOnly {
String getName();
}
interface SchoolRepository extends Repository<School, UUID> {
NamesOnly findOneById(String id);
}

So after reading the documentation and reading other options this is the only solution i find where i can search the result using id and get only field i want in the result since i am only searching using the id so i have to overload the findbyId and since projection interface only change the return type i can not use that so here is what i did .
#Query(value="{_id:?0}",fields="{?1:1,?2:1}")
List<School> findById(String schoolId, String fieldOne,String fieldTwo);
here ?0 is a place holder for schoolId and ?1 and ?2 are the placeholder for the fields name so now i can create these overloaded method which i can use to any no of fields the output is list of school since i am using id which is primary key so its just one school object list so i can just do get(0) to get my school object and it will have all the other fields as null this is the best i could find please share your thought to improve it i would love to hear other solutions .

Related

Handling filtering by a particular field in JPA Spring Boot

I want to implement a filtering feature based on the properties of an entity that I have stored in my db.
I'm using a JPA query to do so. The problem that I'm facing is concerned with entity manager which requires the class of the object that is required to return.
public List<CountryEntity> getSortedCountries(String field, String type) {
return entityManager.createQuery(GET_ALL_SORTED.concat(field).concat(" " + type), CountryEntity.class).getResultList();
}
When I select only one field, let's say the name of the country, the query returns a String and not an object of type CountryEntity.
What is the best approach to handle this problem? Should I create classes for every single case or is there another way that I'm missing?

How do I map "id" property into "id" field in Mongo without #Field annotation?

I have multiple classes with the id field. I would like to store their instances in MongoDB using spring-data-mongodb. I would like to map id property in these classes to id field in Mongo.
So here is what my classes look like:
public class Entity {
private final String id; // = 42
...
}
And here is what I am expecting to be in Mongo collection:
{
"_id": ObjectId("5fba805dfdaaa760974d45de"),
"id": "42"
}
By default, spring-mongodb maps id property to _id field in Mongo. I know that the simplest way to avoid this is to put #org.springframework.data.mongodb.core.mapping.Field("id") annotation on id property in a Java class. But I prefer not to use this annotation since I would like to keep my model independent of Mongo, or Spring, or whatever. Which options are possible here?
Here is what I have tried or checked:
Registering custom AbstractMongoEventListener in order to modify Mongo documents just before they are written to Mongo, or just after they have been read from Mongo. It does not work for me since custom listener is called only during get and insert operations, but not during the update or upsert operations (see discussion here for details).
Providing custom FieldNamingStrategy — it does not work since in the spring-data-mongodb code they use strategy only if field name is not id or _id.
Providing custom converter for each of my classes. I believe it should work. But this approach seems to be too complicated since I have many classes with many properties in each of them and I'm not sure I would like to have many converters with boilerplate code inside.
Any help would be appreciated.
Don't you think that id with _id is already confusing?
If you have a strong valid reason to have an id (different than DB one); give it a name .e.g: version_id, old_id, other_services_id ... some meaningful name.
And yes using #Field in your case is the simplest way

Spring data with MongoDB Views

To improve our query performances and hence the API response times, we created views on MongoDB by aggregating the data. However when we try to use the view using Spring Mongo template, running into several issues like View not supported.
Caused by: com.mongodb.MongoCommandException: Command failed with error 166 (CommandNotSupportedOnView): 'Namespace aiops.hostView is a view, not a collection' on server 192.168.20.166:30011. The full response is {​​​​​​​"ok": 0.0, "errmsg": "Namespace aiops.hostView is a view, not a collection", "code": 166, "codeName": "CommandNotSupportedOnView"}​​​​​​​
at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:175)
at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:303)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:259)
Does Spring support MongoDB views out of the box? any example will greatly help!
Thank you in advance
This is somewhat old, but I will leave my solution in case someone stumbles on this, like I did.
As far as I know, you can't use the usual Spring Data approach: you can't annotate an Entity with the #Document(value="YOUR_VIEW_NAME") annotation and create a related repository extending the MongoRepository class.
But you can query the view directly from the MongoTemplate, passing along the name of your view.
Let's say you have a User entity defined like this:
public class User {
#Id
String id;
String name;
}
Then you can map it to the documents of a view named "userview", and query it like this:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Bob"));
// template is an object of class MongoTemplate that you can inject or autowire
List<User> users = template.find(query, User.class, "userview");
I recently faced the same problem, what #gere said is not entirely correct, you can use a view with spring data repositories but there are some limitations that are related to the limitation of the view itself.
In my case, the problem was that I was using annotation CompositeIndex and Indexed on the document which represents a view, and as MongoDB view uses the underlying collection indexes so it does not have the operation command to create an index for itself and when spring data tries to create an index on that view, MongoDB throws an exception. After removing those annotations, I was able to use them via my repository. I would suggest you use a read-only repository as well to prevent having a save method or delete as I think that is a view limitation too. if you search you can find examples of read-only repositories.
In your case, you need to find what operation you were trying to do on a normal collection that view does not support.

Spring Data- how to tell spring what entities to retrieve

If i have several entites, lets say :
#Entity
class Book{
String name;
Author author;
}
#Entity
class Author{
String name;
City hometown;
}
#Entity
class City{
String cityName;
}
If i want to retrieve all the books, if i use classic JPA Repository and Spring Data and just do a findAll(), it will get me all the books with all the Authors with all their home towns. I know i can use #JsonIgnore, but i think that only prevents whats being returned, not whats being looked up in the database. And also i have methods that DO want to return both books and authors, so #JsonIgnore -ing does not work for me. Is there anything like this ? To tell Spring Data what to look up and what to return ? Any links or guides or methods i don't know of, would be appreciated.
Spring Data has the concept of 'projections' which allow you to return different representations of the same Entity.
Official Documentation:
Spring Data query methods usually return one or multiple instances of
the aggregate root managed by the repository. However, it might
sometimes be desirable to create projections based on certain
attributes of those types. Spring Data allows modeling dedicated
return types, to more selectively retrieve partial views of the
managed aggregates.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
Where a Projection is a 'closed' projection (a projection interface whose accessor methods all match properties of the target aggregate) then the documentation notes that additionally:
Spring Data can optimize the query execution [to select only the relevant fields], because we know about
all the attributes that are needed to back the projection proxy
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces.closed
Spring Data also allows for Projections to be specified dynamically at runtime. See further:
https://github.com/spring-projects/spring-data-commons/blob/master/src/main/asciidoc/repository-projections.adoc#dynamic-projections
First mark your relations as LAZY
Then specify what data needs to be fetched on a per-query basis.
See for example:
https://vladmihalcea.com/eager-fetching-is-a-code-smell/

Spring data mongorepository, find by inner object field

I am developing a simple Social network and need help with mongorepository query.
I have 2 documents:
#Document(collection = "post")
public class Post {
...........
#DBRef
#Field("settings")
private Settings settings;
and
#Document(collection = "settings")
public class Settings {
..............
#Field("privacy_settings")
private PrivacySettings privacySettings;
}
PrivacySettings is an enum with settings ONLY_ME, EVERYONE, FRIENDS.
And the situation is: a friend is viewing on my page and he can see my posts with correct privacy settings(etc. he can see only posts with PrivacySettings: EVERYONE, FRIENDS, but not the ONLY_ME).
Ideas, how to resolve this problem? How to create a correct query?
Solution 1
In Mongo, you can't query of DbRef fields except for Id as no join is supported in this. As read operation is very high I will recommend you to embed part of Setting document in Post instead of referencing it. As mongo DB design suggest if read > write you should embed the document. In this case, the query will be simple.
Solution 2
You can fire two DB queries 1st on Setting document to get the Setting with EVERYONE, FRIENDS the make query on Post document to get all post with Setting in query.
Solution 3
You can use QueryDSL for query on DbRef object easily for reference see this.

Resources