Ausgabe
Ich arbeite mit Spring Boot und MongoDB. Ich suche nach einer Lösung, um eine Liste von Hobbys zu erhalten, aber nicht alle. Die Hobbys müssen die Bedingungen erfüllen (Name oder Beschreibung müssen Suchwort enthalten).
@Document("persons")
@Data
class Person {
@Id
private String personId;
private String name;
private List<Hobby> hobbies;
}
@Data
class Hobby {
private String name;
private String description;
private String notImportantField;
}
Beispiel
Ich möchte eine Person mit einer reduzierten Liste von Hobbys erhalten (alle Hobbys müssen die gesuchte Phrase in einem ihrer Felder enthalten).
Personendokument aus der Datenbank
{
"_id" : ObjectId("id1"),
"name" : "some person",
"hobbies" : [
{
"name" : "A",
"description" : "AB",
"notImportantField" : "ABCDEF"
},
{
"name" : "ABC",
"description" : "ABCD",
"notImportantField" : "ABCDEF"
}
]
}
Was ich erhalten möchte:
- Ich möchte eine Person mit ID
id1
und suche nach Phrasenab
in den Hobbys der Person. Ich sollte eine Liste mit 2 Hobbys erhalten (Beschreibung des ersten Hobbys enthältab
, Name und Beschreibung des zweiten Hobbys enthältab
) - Ich möchte eine Person mit ID
id1
und suche nach Phrasend
in den Hobbys der Person. Ich sollte eine Liste mit 1 Hobby erhalten (die Beschreibung des zweiten Hobbys enthältd
)
Ich habe so etwas versucht, aber ich bekomme eine Person mit all ihren Hobbys.
@Repository
interface PersonRepository extends MongoRepository<Person, String> {
@Query("{'$and': [" +
"{'_id': :#{#personId}}," +
"{'$or':[" +
"{'hobbies.name': {$regex: :#{#searchPhraseRegex}, $options: 'i'}}," +
"{'hobbies.description': {$regex: :#{#searchPhraseRegex}, $options: 'i'}}" +
"]}" +
"]}")
List<Person> method(@Param("personId") String personId, @Param("searchPhraseRegex") String searchPhraseRegex);
}
Die Ergebnismethode sollte eine Person mit gefilterten Hobbys oder nur eine Liste von Hobbys zurückgeben. Vielen Dank im Voraus für Hilfe.
UPDATE: BEHOBEN
Danke @user20042973 für die Hilfe 🙂 Ich habe Ihre Abfrage verwendet und sie ein wenig geändert, damit sie mit meiner Abfrage im Mongo-Repository übereinstimmt. Es funktioniert so, wie ich es erwartet habe. Die Ergebnismethode lautet:
@Repository
interface PersonRepository extends MongoRepository<Person, String> {
@Aggregation(pipeline = {
"{'$match': {'_id': :#{#personId}}}",
"{'$addFields': {'hobbies': {'$filter': {" +
"'input': '$hobbies', " +
"'cond': " +
"{'$or': [" +
"{'$regexMatch': {'input': '$$this.name', 'regex': :#{#searchPhraseRegex}, 'options': 'i' }}," +
"{'$regexMatch': {'input': '$$this.description', 'regex': :#{#searchPhraseRegex}, 'options': 'i' }}" +
"]}" +
"}}}}"
})
Optional<Person> findPersonByIdAndFilterHobbies(@Param("personId") String personId, @Param("searchPhraseRegex") String searchPhraseRegex);
}
Hinweis: Für die Suche ab
müssen wir zB .*ab.*
als Methodenargument übergeben searchPhraseRegex
.
Lösung
Helpfully, getting a filtered list of objects from an array can be done using the $filter
operator. The operator takes an array as input and can process each item individually via an expression. In your situation that expression would include a $regexMatch
to look for the value in the string(s) of interest. So the stage would look something like this:
{
"$addFields": {
hobbies: {
$filter: {
input: "$hobbies",
cond: {
$or: [
{
$regexMatch: {
input: "$$this.name",
regex: "d",
options: "i"
}
},
{
$regexMatch: {
input: "$$this.description",
regex: "d",
options: "i"
}
}
]
}
}
}
}
}
Sample Mongo Playground example is here.
From your question it’s not quite clear if you will separately be using this as selection criteria for the document itself. I’ve left the leading $match
stage to just use _id
for the moment, but of course you can add any other filters to it (such as 'hobbies.name': /d/i
) as needed.
Ich bin persönlich nicht vertraut genug mit Spring Boot, um zu sagen, wie die genaue Syntax zum Erstellen einer solchen Pipeline lautet, aber ich weiß, dass Aggregationen unterstützt werden.
Beantwortet von – user20042973
Antwort geprüft von – Jay B. (FixError Admin)