Масштабирование с помощью MongoDB для поиска различий

#java #mongodb #hibernate #quarkus #quarkus-panache

#java #mongodb #спящий режим #quarkus #quarkus-panache

Вопрос:

У меня есть документы с массивами «тегов» в качестве свойств. Теперь я хочу запросить все отдельные элементы тегов.

 { 
  "name": "test1",
  "tags": ["tag1","tag2", "tag3"]
},
{
  "name": "test2",
  "tags": ["tag1"]
}
 

Решение в оболочке mongo:

 db.ApiModel.distinct("tags")

 

что дает мне:

 ["tag1", "tag2", "tag3"]
 

Но как я могу добиться того же результата с помощью Panache? PanacheMongoEntity не предлагает конкретного метода distinct. Я также не знаю, как использовать этот find метод для достижения моей цели или если это вообще возможно с помощью этого метода.

Все, о чем я мог подумать, это найти все теги с find("tags", "*") помощью (является ли * подстановочным знаком?), А затем иметь дело с дубликатами в Java, но я не верю, что это предполагаемое использование.

Комментарии:

1. Я думаю, вы можете использовать PanacheMongoEntityBase#stream метод, который возвращает a Stream<T> , который, в свою очередь, может быть использован для получения ваших различных значений определенного поля ( Stream#distinct ).

2. При переходе из спящего режима с SQL это выглядит как «плохой код», потому что я извлекаю все, а затем сужаю его. Но я думаю, что это правильный путь? Есть ли способ проверить запрос, который он создает в журналах?

Ответ №1:

Вы можете использовать любой из двух методов, чтобы получить distinct tags из коллекции test .

 public List<String> getDistinctTags() {
        return Tags
                .<Tags>mongoCollection()
                .distinct("tags", String.class)
                .into(new ArrayList<String>());
}

public List<String> getDistinctTags() {
        return Tags
                .<Tags>streamAll()
                .flatMap(e -> e.tags.stream())
                .distinct()
                .collect(toList());
}
 

Предполагая Tags , что класс определен следующим образом и представляет объект Panache:

 @MongoEntity(collection="test")
public class Tags extends PanacheMongoEntity {
    public String name;
    public List<String> tags;
    // ...
}
 

Комментарии:

1. Спасибо! Значит, сам запрос выполняется только тогда, когда я вызываю .collect()? Потому что в противном случае streamAll () (он извлекает каждый документ в моей коллекции?) будет выполняться сначала, и я получаю все, а затем использую distinct в java, а не в mongodb? Или я думаю, что слишком ориентирован на SQL?

2. Хорошо, речь идет о втором методе getDistinctTags() . Запрос фактически извлекает все документы как a java.util.stream.Stream , к которым применяются методы Stream flatMap distinct и collect . В первом getDistinctTags() случае distinct применяется на сервере, и результаты возвращаются.

3. PanacheMongoEntity.streamAll Возвращает a Stream со всеми объектами типа.

4. Итак, первое решение было бы более эффективным с точки зрения производительности, верно? Я только что пришел из мира SQL и извлекаю всю таблицу, а затем выполняю операции с ней на java, что было бы плохой практикой.

5. Запрос distinct выполняется на сервере, и вы получаете результат операции в своем Java-приложении. Да, запрос, выполняемый на сервере, более эффективен, и вы можете увидеть прирост производительности, основанный на ваших данных и других факторах, таких как сеть и т.д..