Find resource by name which contains all search words - spring-data-jpa

I have a repository:
public interface ItemRepository extends PagingAndSortingRepository<Item, Long> {
List<Item> findByNameContainingIgnoreCase(#Param("name") String name);
}
I would like the find method to accept a list of words and find items which contain all words in their name. Something like:
List<Item> findByNameContainingAllIgnoreCase(#Param("name") String[] name);
Is this possible?

Related

How to use criteria query on refrence collection in mongo db

How do I find all the person which are having city ="XYZ" in Address collection
public class Person {
#Id
private String id;
private String description
#DBRef
private Address address;
// Getters and Setters
}
public class Address
{
#Id
private String id;
private String area
private String city
// Getters and Setters
}
Mongo understands #DBRef as a reference to another document, in this case, an Address document and ultimately when the object is loaded from MongoDB, those references will be eagerly resolved and this will get populated to the user as a HATEOAS friendly link. You will get back a mapped object that looks the same as if it had been stored embedded within your master document.
You can define your repository, which will map the endpoints to your database, for the given object, like PersonRepository defined below as an example:
import com.mycompany.domain.Person;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface PersonRepository extends MongoRepository<Person, String> {
List<Person> findByCity(#Param("city") String city);
}
Another way you could go around this using the query criteria methods is executing two queries.
First query would be to fetch the address documents which have the city = "XYZ". Resolve the ids from the list returned.
Generate another query on the Person entity using the ids from the previous operation.
The following demonstrates this approach
Query addressQuery = new Query(where("city").is("XYZ"));
addressQuery.fields().include("_id");
List<Address> addressList = mongoTemplate.find(addressQuery, Address.class, "address"); // get the addresses list that satisfy the given city criteria
// Resolve the ids for the addresses
final List<ObjectId> addressIds = new ArrayList<ObjectId>(addressList.length);
for(final Address address : addressList) {
addressIds.add(new ObjectId(address.getId()));
}
// Get the Person list using the ids from the previous operation
Query personQuery = new Query(where("address.$id").in(addressIds));
List<Person> list = mongoTemplate.find(personQuery, Person.class, "person");
If you knew the address id before hand you can then use a custom query:
public interface PersonRepository extends MongoRepository<Person, String> {
#Query("{ 'address': {'$ref': 'address', '$id': { '$oid': ?0 } } }")
List<Person> findByAddres(String addressIdAsString);
}

springdata mongo repository method to return specific document property list

using spring data for mongodb, how do I specify the return type of the repository method to include a particular property from the document?
Ex:
#Document (collection = "foo")
class Foo {
String id
String name
... many more attributes
}
repository:
interface FooRepository extends MongoRepository<Foo, String> {
#Query { value = "{}", fields = "{'name' : 1}" }
List<String> findAllNames()
}
Above findAllNames works as expected and fetches only name property from the document. However spring data returned object is a string representation of Foo object which has id and name properties with values and remaining attributes as null.
Instead of Foo objects, I need to fetch List<String> which represents names.
As of now, I used a custom interface to achieve this. Moved the findAllNames() method from Spring data repository interface to my custom interface
interface FooRepositoryCustom {
List<String> findAllNames()
}
interface FooRepository extends MongoRepository<Foo, String>, FooRepositoryCustom {
}
#Component
class FooRepositoryImpl implements FooRepositoryCustom {
#Autowired
MongoOperations mongoOperations;
List<String> findAllNames() {
//using mongoOperations create the query and execute. Return the property values from document
}
}

Spring Data REST custom finder for JpaRepository

I am looking to build a REST interface with a generic finder. The idea is to provide a search form where users can get all records by not providing any parameter or refine their search results by typing any combination of the fields.
The simple example I have annotates the JpaRepository with #RestResource which provides a nice out of the box way to add finders either by using #Query or by method name conventions
#RestResource(path = "users", rel = "users")
public interface UserRepository extends JpaRepository<User, Long>{
public Page<User> findByFirstNameStartingWithIgnoreCase(#Param("first") String fName, Pageable page);
}
I am looking to add a custom finder that would map my parameters and would leverage the paging, sorting and REST support where the actual implementation query will be composed dynamically (probably using QueryDSL) the method will have n parameters (p 1 ... p n) and will look like:
public Page<User> findCustom(#Param("p1") String p1, #Param("p2") String p2, ... #Param("pn") String pn, Pageable page);
I have tried the approach described in:
http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations
but my custom method is not available from the repository's REST interface (/users/search)
I hope someone already figured this out and would be kind to give me some direction.
Try something like this but of course adopted to your scenario:
public interface LocationRepository extends CrudRepository,
PagingAndSortingRepository,
LocationRepositoryExt {
}
public interface LocationRepositoryExt {
#Query
public List findByStateCodeAndLocationNumber(#Param("stateCode") StateCode stateCode, #Param("locationNumber") String locationNumber);
}
class LocationRepositoryImpl extends QueryDslRepositorySupport implements LocationRepositoryExt {
private static final QLocation location = QLocation.location;
public LocationRepositoryImpl() {
super(Location.class);
}
#Override
public Page findByStateAndLocationNumber(#Param("state") State state, #Param("locationNumber") String locationNumber, Pageable pageable) {
List locations = from(location)
.where(location.state.eq(state)
.and(location.locationNumber.eq(locationNumber)))
.list(location);
return new PageImpl(locations, pageable, locations.size());
}
}

Structuring REST URI's with Jersey

New to Jersey(REST Framework for Java) and I'm trying to setup two resources, in two separate classes that share a root path, and I'm having a problem.
So, I have something like:
#Path("/users")
public class User extends RestSupport {
#GET
#Path("/{user_uuid}")
public String get(#PathParam("user_uuid") String uuid) {
return "Hello User " + uuid;
}
}
The above class works. However, I want to create a child resource in a separate class. But when I do this, it seems to create a URI naming conflict. So, here, I want to get all the pets for a particular users
#Path("/users")
public class Pets extends RestSupport {
#GET
#Path("/{user_uuid}/pets")
public String get(#PathParam("user_uuid") String uuid) {
return "Hello Pets " + uuid;
}
}
These top-level resources have lots of child resources, so I'm looking for the best way to organize them. Any help would be appreciated.
Change the path of Pets class from #Path("/users")to#Path("/users/{user_uuid}/pets")
Don't add the HTTP annotation #GET on your Users root resource method if you want Jersey to delegate calls to a child resource. Consider a User class:
public class User {
String uuid;
User(String id) { this.uuid = id; }
#GET
public String get() { return "Hello user " + uuid; }
#GET
#Path("/pets")
public String getPets() { return "Hello pets " + uuid; }
}
and then adjust your Users resource:
#Path("/users")
public class Users {
#Path("/{user_uuid}")
public User get(#PathParam("user_uuid") String uuid) {
// Get the user from the DAO here...
return new User(uuid);
}
}

Using the $in operator through Morphia - doing it wrong?

I have the following Play Framework entity (using Morphia for persistence) as part of a generic blogging app:
#Entity
public class Comment extends Model {
...
#Reference
#Indexed
public SiteUser commenter;
public static List<Comment> getLastCommentsByUsers(final List<SiteUser> users) {
final Query<Comment> query ds().createQuery(Comment.class);
query.field(commenter).hasAnyOf(users);
return query.asList();
}
}
SiteUser:
#Entity(noClassnameStored=true)
public class SiteUser extends AbstractUser {
public String realName;
}
AbstractUser:
public class AbstractUser extends Model {
#Indexed(value= IndexDirection.DESC, unique = true)
public String emailAddress;
#Required
public String password;
}
The method getLastCommentsByUsers() is supposed to return all comments by the users in the users parameter, but I always get an empty List back. The reason that Commment is a separate collection is to be able to retrieve last X Comments by certain users across their associated Posts, which isn't possible if the Comment is embedded in the Post collection.
Is there something wrong with my query (should I be using something other than hasAnyOf), or is it a problem with the relationship mapping - should I be using ObjectId instead?
I use the in() method with a list or set and its working perfectly. Here's a snippet:
List<String> keywordList;
List<Product> products = Product.find().field("keywords").in(keywordList).asList();
This should work for collection of embedded or references too.
You should use List<Key<SiteUser>> to query:
public static List<Comment> getLastCommentsByUsers(final List<SiteUser> users) {
final Query<Comment> query ds().createQuery(Comment.class);
query.field(commenter).hasAnyOf(toKeys(users)); // convert to keys
return query.asList();
}
public static List<Key<SiteUser>> toKeys(List<SiteUser> users) {
List<Key<SiteUser>> keys = new ArrayList<Key<SiteUser>>();
for(SiteUser user: users) {
keys.add(ds().getMapper().getKey(user));
}
return keys;
}
Or you can just get the keys by:
List<Key<SiteUser>> keys = ds().createQuery(SiteUser.class).query().filter(...).asKeyList();