How to only retrieve the nested document mongodb and spring boot - spring-boot

I have the following document and nested document.
class Foo {
public String name;
public String description;
public LocalDateTime someDate;
}
#Document
class Bar {
#Id
public String id;
public String details;
public List<Foo> foos;
}
My custom query looks as follows:
Query query = new Query(
Criteria.where("foo.name").is("Some name").and("id").is("myId")
);
List<Bar> resultList = operations.find(query, Bar.class);
I want to retrieve the the single Foo document that matches "Some name". And not the Bar document with the Foo list. How would I do this?
Thanks

If your Foo class doesn't have a collection in database and it's embedded in Bar as you described in your question. You will need to create a custom repository to get what you are looking for.
interface BarRepository extends BarCustomRepository, MongoRepository<Bar, String> {
}
interface BarCustomRepository {
Foo findFooByName(String fooName);
}
class BarRepositoryImpl implements BarCustomRepository {
#Autiwired
private MongoTemplate mongoTemplate;
#Override
Foo findFooByName(String fooName) {
Bar bar = mongoTemplate.findOne(new Query ( Criteria.where("foos.name").is(fooname)), Bar.class);
Foo foo = bar.getFooByName(fooName);// implement this method in your Bar class. // to Get a foo by fooName from foos list
return foo;
}
}
I hope that helps.

Related

Spring Boot: #Value returns null

I am new to springmvc, so the question may sounds dumb.
I have similar issue to this Spring Boot: #Value returns always null. Example that i have:
System Properties
<sysproperty key="bar" value="bar_value" />
Bean Configuration
#Configuration
public class Foo {
#Value("${bar}")
private String bar;
#Bean(name = "getBar")
public String getBar() {
return bar;
}
}
Access Bean (index.jsp)
String bar = webApplicationContext.getBean("getBar", String.class); // returns null instead of "bar_value"
However, if i change the Bean Configuration to
#Configuration
public class Foo {
#Value("${bar}")
#Bean(name = "getBar")
public String getBar(String bar) {
return bar;
}
}
and then accessing it, the returned value is correct, what could be the reason of this? I know that things are controlled by the framework so i don't have much visibility about the instantiation process of the app, help is well appreciated.
Please make use of Setter Injection. Hope it will resolve your issue.
public class Foo {
private String bar;
#Autowired
public setBar(#Value("${bar}") String bar) {
this.bar = bar;
}
// standard getter
#Bean(name = "getBar")
public String getBar() {
return bar;
}
}

Spring Boot - MongoDB - Inheritance

I'm running into something odd with inheritance and mongodbrepositories.
I have the following:
`
#Document
public class Base {
public String fieldA;
}
public class Derived extends Base {
public String fieldB;
}
public interface DerivedRepository extends MongoRepository<Base, String> {
List<Derived> findByFieldA(String fieldA);
}
`
When inserting i get
Inserting DBObject containing fields: [_class, _id, fieldA, fieldB ]
in collection: base
When i do findByFieldA('some value') on the repository i get the following:
find using query: { "fieldA" : "some value" } fields: null for class:
class Derived in collection: derived
Any idea what is going on here? And how can I fix this, either by saving it to the proper derived collection or by querying from the base collection.
Regards,
First, I would make Derived class as document since the parent is going to be shared among many implementations.
public class Base {
public String fieldA;
}
#Document
public class Derived extends Base {
public String fieldB;
#Override
public String toString() {
return "{fieldA: " + getFieldA() + ", fieldB: " + fieldB + "}";
}
}
Second, change the repository specification with the type of document (class marked as #Document) as:
public interface DerivedRepository extends MongoRepository<Derived, String> {
List<Derived> findByFieldA(String fieldA);
List<Derived> findByFieldB(String fieldB);
}
I added extra method findByFieldB(String fieldB) to explain more.
With these changes, you should be able to query either with fieldA or fieldB as below:
public class SpringBootMongoApplication {
#Autowired
private DerivedRepository derivedRepository;
public void testMethod() throws Exception {
Derived derived1 = new Derived();
derived1.setFieldB("fieldB1");
derived1.setFieldA("fieldA1");
Derived derived2 = new Derived();
derived2.setFieldB("fieldB2");
derived2.setFieldA("fieldA2");
this.derivedRepository.save(Arrays.asList(derived1, derived2));
List<Derived> deriveds = this.derivedRepository.findByFieldA("fieldA1");
System.out.println(deriveds);
List<Derived> deriveds1 = this.derivedRepository.findByFieldB("fieldB2");
System.out.println(deriveds1);
}
}
The output should be:
[{fieldA: fieldA1, fieldB: fieldB1}]
[{fieldA: fieldA2, fieldB: fieldB2}]
You can also verify the object persisted and their types with mongo query as below:
I have created an Spring Boot sample app which you can find in Github.

OpenSessionInView vs. Transactional? (Spring/Hibernate/JPA)

I have a JPA entity with Lazy loaded collection on it. I do not need the collection every time.
#Entity(name = "Foo")
#Access(AccessType.FIELD)
#Table(name = "TEST", schema = "TEST")
public class Foo implements Serializable {
private static final long serialVersionUID = 1L;
#OneToMany(mappedBy="foo", targetEntity=Bar.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private List<Bar> bars;
}
#Entity(name = "Bar")
#Access(AccessType.FIELD)
#Table(name = "TEST", schema = "TEST")
public class Bar implements Serializable {
private static final long serialVersionUID = 1L;
#ManyToOne(targetEntity = Foo.class)
#JoinColumn(name = "FOO_ID", referencedColumnName = "ID")
private Foo foo;
}
I have a few methods on a service class that perform a lot of database interactions and at the end save a Foo entity to the database. I need this to happen for about a 100 items in a collection.
#Service
public class FooService {
#Autowired
private FooRepository fooRepository;
public void processAllFoos() {
fooRepository.findAll().forEach(foo -> {
processFoo(foo);
});
}
private void processFoo(Foo foo) {
foo.getBars().forEach(bar -> {
// Do a lot of time consuming stuff here that involves
// entities of other types and modify each bar object
});
fooRepository.save(foo);
}
}
processAllFoos gets called from a #RESTController whenever it gets a request.
However, I do not want processAllFoos to be wrapped in a single database transaction, because that locks up the entire Foo table till the business logic is executed for all Foos.
If I make the processFoo method #Transactional I get the LazyInitializationException which complains that the Hibernate session is non-existent. To make this work I need to make all methods in the call stack #Transactional so that the nested methods can join onto the calling method's transaction. But this locks the entire Foo table as mentioned above.
Adding a OpenSessionInViewFilter for the dispatcher servlet solves my problem but I've read that there are issues with performance and entity detaching/reattaching (which I do in other parts of the application) with this approach.
Is there a way I can do what I want to without using the OpenSessionInView approach? What other vulnerabilities am I adding by using this approach?
Spring/Hibernate 4.x
Based on the answer below, I was able to do the following:
#Service
public class FooService {
#Autowired
private FooRepository fooRepository;
#Autowired
private TransactionTemplate transactionTemplate;
public void processAllFoos() {
fooRepository.findAll().forEach(foo -> {
transactionTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
try {
processFoo(foo);
status.flush();
} catch(Exception e) {
status.setRollbackOnly();
}
return null;
}
});
});
}
private void processBar(Foo foo) {
foo.getBars().foreEach(bar -> {
// Do a lot of time consuming stuff here that involves
// entities of other types and modify each bar object
});
fooRepository.save(foo);
}
}
OpenSessionInViewFilter commonly used to solve LazyInitialization problem in View layer (UI components or page templates), because View layer can't and must not manage transactions directly.
In your case another way to get all the Bar objects can be applied.
First You get all the Foo object ids instead to get fully objects.
Second Use Foo ids collection to iterate thru related Bar objects.
Third If you don't want one BIG transaction then you can use Spring Transaction template to manage transactions explicitly.
Your code example may look like this:
#Service
public class FooService {
#Autowired
private FooRepository fooRepository;
#Autowired
private BarRepository barRepository;
#Autowired
private TransactionTemplate transactionTemplate;
public void processAllFoos() {
final List < Long > fooIdList = transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return fooRepository.findIdList();
}
});
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
barRepository.findByFooIdList(fooIdList).forEach(bar - > {
processBar(bar);
});
return null;
}
});
}
private void processBar(Bar bar) {
// Do a lot of time consuming stuff here that involves
// entities of other types and modify each bar object
barRepository.save(bar);
}
}
Example below shows how to solve your task without some performance overheads. But you should understand that if Foo and Bar tables linked with foreign key constraint, then related record in Foo table may be blocked by RDBMS each time you update row in Bar table.

Unable to get a specific properties with #ConfigurationProperties

I would like to retrieve a property but when a dot is used, I can't, I get null,
Is there a way to do it still using #ConfigurationProperties ?
See the example:
#Component
#ConfigurationProperties(prefix = "prop.foo")
public class Test {
//This is working
private String myVal;
//This is not working
private String barAnotherVal;
public void setMyVal(String myVal) {
this.myVal= myVal;
}
public void setBarAnotherVal(String barAnotherVal) {
this.barAnotherVal= barAnotherVal;
}
}
application.properties:
prop.foo.myVal
prop.foo.bar.anotherVal
To set barAnotherVal on Test your property needs to be prop.foo.barAnotherValue.
If you want to use prop.foo.bar.anotherValue then you need a property for bar on Test. The bar type should then have the anotherValue property. Something like this:
#Component
#ConfigurationProperties(prefix = "prop.foo")
public class Test {
private String myVal;
private Bar bar = new Bar();
public void setMyVal(String myVal) {
this.myVal = myVal;
public Bar getBar() {
return this.bar;
}
public static class Bar {
private String anotherVal;
public void setAnotherVal(String anotherVal) {
this.anotherVal = anotherVal;
}
}
}

How to get an array of members of an array

Suppose I have a class
public class Foo
{
public Bar Bar { get; set; }
}
Then I have another class
public class Gloop
{
public List<Foo> Foos { get; set; }
}
What's the easiest way to get a List<Bar> of Foo.Bars?
I'm using C# 4.0 and can use Linq if that is the best choice.
UPDATE:
Just for a little dose of reality, the reason for this is that I have a Windows Service class that contains an inner ServiceBase derived class as a property. So I end up with code like this:
public class Service
{
public ServiceBase InnerService { get; set; }
}
public class ServiceHost
{
private List<Service> services = new List<Service>();
static void Main()
{
// code to add services to the list
ServiceBase.Run(services.Select(service => service.InnerService).ToArray());
}
}
This one's simple, if I've understood you rightly:
List<Foo> foos = gloop.Foos; // Or wherever you're getting it from
List<Bar> bars = foos.Select(foo => foo.Bar)
.ToList();
If you only need an IEnumerable<Bar> you can just use Select without the call to ToList. Of course you don't need the foos local variable if you don't want it - you can just have a single statement. I've only separated them out in case you've got an existing List<Foo> or Foo[] (you mention arrays in your subject line).
var bars = gloop.Foos.Select(foo => foo.Bar);

Resources