2016-04-13 3 views
2

Ich benutze Spring Boot mit Mongodb. Ich habe PagingAndSortingRepository Repository erweitert und hinzugefügt, um die folgende FunktionÜbergeben Array von Reg-Ausdrücke zu Frühjahr basierte Mongo @Query

@Query("{'title':{ $nin: [?0]}}") 
List<Item> findItem(String[] exclude); 

Ich möchte es in der Lage sein eine Reihe von regulären Ausdrücken passieren wie/Hund /,/cat /,/Pferd/ein beliebiges Element auszuschließen, kann habe einen davon im Titel.

Die obige Funktion funktioniert nicht, da der Ausschluss in eine Zeichenfolge konvertiert wird. Wie kann ich ein Array von regulären Ausdrücken übergeben, um das oben genannte zu tun?

+0

Es scheint so, als ob Sie den * Fall * gefunden haben, der nicht direkt mit "Standard" -Abfrage-Methoden oder mit der @Query-Annotation (ab heute) gelöst werden kann. Möchten Sie Ihre Repository-Instanz in einem Controller verwenden? Wenn ja, kann ich eine Idee haben. –

+0

Ja Ich verwende den Repo in einer @RestController-Instanz. Ich dachte daran, das Array in einen einzigen Regex umzuwandeln und $ regex stattdessen zu verwenden, aber es ist keine sehr saubere Lösung. – jvence

+0

Ihre einzige Regex würde wahrscheinlich Pipes enthalten und ich bin mir ziemlich sicher, dass Spring gut auf Pipes in URLs reagiert. –

Antwort

2

Sie können es ausarbeiten, indem Sie ein Querydsl Prädikat in einer Ihrer Controller-Methode verwenden.

so etwas zu Ihrem Controller hinzufügen:

@RequestMapping(value="/search/findByNameRegexNotIn", method = RequestMethod.GET) 
@ResponseBody 
public List<Item> findByNameRegexNotIn(@RequestParam(name = "name") List<String> names) { 
    // build a query predicate 
    BooleanBuilder predicate = new BooleanBuilder(); // comes from the Querydsl library 
    for (String name : names) { 
      predicate.and(QItem.item.name.contains(name).not()); // the QItem class is generated by Querydsl 
    } 

    List<Item> items = (List<Item>)repository.findAll(predicate); 

    return items; 
} 

Sie können einen Pageable Parameter natürlich hinzufügen und eine Seite <Artikel> statt einer Liste zurück.


Edit: Eine andere Lösung, wenn Sie Querydsl für diesen einzigen Zweck verwenden, besteht darin, die Standardbindungen Ihres Abfrageparameters zu überschreiben.

public interface ItemRepository extends CrudRepository<Item, String>, 
    QueryDslPredicateExecutor<Item>, QuerydslBinderCustomizer<QItem> { 

    @Override 
    default public void customize(QuerydslBindings bindings, QItem item) { 
     bindings.bind(item.name).all(
      (path, values) -> path.matches(StringUtils.collectionToDelimitedString(values, "|")).not()); 
     // disable query on all parameters but the item name 
     bindings.including(item.name); 
     bindings.excludeUnlistedProperties(true); 
    } 
} 

Die Controller-Methode:

@RequestMapping(value="/search/query", method = RequestMethod.GET) 
@ResponseBody 
public List<Item> queryItems(
     @QuerydslPredicate(root = Item.class) Predicate predicate) { 
     List<Item> items = (List<Item>)repository.findAll(predicate); 

     return items; 
    } 


Edit: Wenn Sie nicht die Standard QuerydslBinderCustomizer # customize Sie wan't außer Kraft zu setzen, können Sie auch Ihr eigenes Bindemittel implementieren und in die angeben Controller-Methode.

public interface ItemRepository extends CrudRepository<Item, String>, 
    QueryDslPredicateExecutor<Item> { 
    ... 
} 

Die Controller-Methode:

@RequestMapping(value="/search/query", method = RequestMethod.GET) 
@ResponseBody 
public List<Item> queryItems(
     @QuerydslPredicate(root = Item.class, bindings = ItemBinder.class) Predicate predicate) { 
     List<Item> items = (List<Item>)repository.findAll(predicate); 

     return items; 
    } 

Die Bindemittelklasse:

class ItemBinder implements QuerydslBinderCustomizer<QItem> { 

@Override 
public void customize(QuerydslBindings bindings, QItem item) { 
    bindings.bind(item.name).all(
      (path, values) -> path.matches(StringUtils.collectionToDelimitedString(values, "|")).not() 
    ); 
    bindings.including(item.name); 
    bindings.excludeUnlistedProperties(true); 
} 

}


Edit: im Interesse über die Vollständigkeit und diejenigen, die nicht wollen, über Querysl zu hören. Verwenden der in Spring Data Mongodb Reference vorgeschlagenen Lösung.

eine Schnittstelle benutzerdefinierte Repository definieren:

interface ItemRepositoryCustom { 

    public Page<Item> findByNameRegexIn(Collection<String> names, Pageable page); 

} 

eine benutzerdefinierte Repository Implementierung definieren (Impl postfix erforderlich!):

public class ItemRepositoryImpl implements ItemRepositoryCustom { 

    @Autowired 
    private MongoOperations operations; 

    @Override 
    public Page<Item> findByNameRegexNotIn(Collection<String> names, Pageable pageable) { 
     String pattern = StringUtils.collectionToDelimitedString(names, "|"); 
     // this time we use org.springframework.data.mongodb.core.query.Query instead of Querydsl predicates 
     Query query = Query.query(where("name").regex(pattern).not()).with(pageable); 

     List<Item> items = operations.find(query, Item.class); 
     Page<Item> page = new PageImpl<>(items, pageable, items.size()); 

     return page; 
    } 

} 

Jetzt ItemRepositoryCustom einfach erweitern:

public interface ItemRepository extends MongoRepository<Item, String>, ItemRepositoryCustom { 

... 

} 

Und du bist fertig!

+0

Danke! werde es versuchen und auf dich zurückkommen. – jvence

+0

@jvence Ich habe meine Antwort mit einer alternativen Lösung bearbeitet (ich habe interessante Dinge dank dir entdeckt;)) –

+0

@jvence Und eine dritte (und letzte) Alternative. –

Verwandte Themen