Spring Data + MongoDB GridFS доступ через репозиторий возможен?

Недавно я обнаружил GridFS, которую хотел бы использовать для хранения файлов с метаданными. Я просто подумал, можно ли использовать MongoRepository для запроса GridFS? Если да, может кто-нибудь привести мне пример?

Я бы также взял решение с использованием Hibernate, если оно есть.

Причина в следующем: мои метаданные содержат много разных полей, и было бы намного проще запросить репозиторий, чем написать несколько new Query(Criteria.where(...)) для каждого сценария. И я надеюсь, что мог бы просто взять объект Java и предоставить его через REST API без самого файла.

РЕДАКТИРОВАТЬ: я использую

  • Spring 4 Beta
  • Spring Data Mongo 1.3.1
  • Бета-версия Hibernate 4.3

person Benjamin M    schedule 27.09.2013    source источник
comment
вы нашли решение этого вопроса? У меня такая же проблема.   -  person Sami    schedule 05.08.2014
comment
Привет. Я добавил ответ ниже с моим текущим решением   -  person Benjamin M    schedule 05.08.2014


Ответы (2)


Есть способ решить эту проблему:

@Document(collection="fs.files")
public class MyGridFsFile {

    @Id
    private ObjectId id;
    public ObjectId getId() { return id; }

    private String filename;
    public String getFilename() { return filename; }

    private long length;
    public long getLength() { return length; }

    ...

}

Для этого вы можете написать обычный Spring Mongo Repo. Теперь вы можете хотя бы запросить коллекцию fs.files с помощью Spring Data Repo. Но: таким образом вы не можете получить доступ к содержимому файла.

Для получения самого содержимого файла у вас есть (как минимум) 2 варианта:

  1. Используйте file = gridOperations.findOne(Query.query(Criteria.where("_id").is(id))); InputStream is = file.getInputStream();

  2. Взгляните на исходный код GridFSDBFile. Здесь вы можете увидеть, как он внутренне запрашивает коллекцию fs.chunks и заполняет InputStream.

(Вариант 2 действительно низкоуровневый, вариант 1 намного проще, и этот код поддерживается разработчиками MongoDB-Java-Driver, хотя вариант 1 был бы моим выбором).


Обновление записей GridFS:

  • GridFS не предназначена для обновления содержимого файлов!
  • Хотя может быть полезно только обновление поля metadata. Остальные поля немного статичны.

Вы должны иметь возможность просто использовать свой собственный метод MyGridFsFileRepo update. Я предлагаю только создать сеттер для поля metadata.


Разные метаданные для разных файлов:

Я решил это, используя класс abstract MyGridFsFile с общими метаданными, то есть:

@Document(collection="fs.files")
public abstract class AbstractMyGridFsFile<M extends AbstractMetadata> {

    ...

    private M metadata;
    public M getMetadata() { return metadata; }
    void setMetadata(M metadata) { this.metadata = metadata; }

}

И, конечно же, с каждым имплементом связан свой собственный AbstractMetadata импл. Что я сделал? AbstractMetadata всегда имеет поле с именем type. Таким образом, я могу найти нужный AbstractMyGridFsFile имп. Хотя у меня также есть общий абстрактный репозиторий.

Кстати: тем временем я перешел с Spring Repo на простой доступ через MongoTemplate, например:

protected List<A> findAll(Collection<ObjectId> ids) {
    List<A> files = mongoTemplate.find(Query.query(Criteria
            .where("_id").in(ids)
            .and("metadata.type").is(type) // this is hardcoded for each repo impl
    ), typeClass); // this is the corresponding impl of AbstractMyGridFsFile
    return files;
}

Надеюсь это поможет. Я могу написать больше, если вам понадобится дополнительная информация по этому поводу. Только скажи мне.

person Benjamin M    schedule 05.08.2014
comment
Спасибо за вашу помощь. Но есть ли у вас файл как часть класса MyGridFsFile и как его сохранить в репозиториях? - person Sami; 05.08.2014
comment
В моем репозитории есть собственный метод, который использует gridFsOperations.save(...) для сохранения новых файлов. Сам InputStream не является частью MyGridFsFile, я получаю его через myRepo.getInputStreamForFile(MyGridFsFile file). Затем этот метод вызывает gridFsOperations.findOne(/* via file.getId() */).getInputStream(). ... Конечно, вы можете внедрить механизм извлечения InputStream в свой MyGridFsFile, но тогда у вас будет некоторая логика кода внутри этого POJO, что нехорошо, но это сработает. - person Benjamin M; 05.08.2014
comment
Я все еще не понимаю, как file.getId() будет соответствовать идентификатору файла в fs.files? Вы храните свой MyGridFSFile объект в обычном документе Mongo и файл в GridFS? Если да, то как они связаны? - person Sami; 06.08.2014
comment
ЧАСТЬ 1: Итак, давайте начнем с самого начала! GridFS - это в основном две коллекции MongoDB: fs.files и fs.chunks. fs.files хранит такие вещи, как id, filename, md5 и т. Д., А fs.chunks хранит содержимое файла. Поэтому, когда вы используете GridFS для хранения файла, он просто создает запись в fs.files и (в зависимости от размера файла) несколько записей в fs.chunks. GridFS - это не отдельное хранилище данных, это просто две стандартные коллекции Mongo. Хотя нетрудно сохранить файл с помощью gridFsTemplate, а затем выполнить обычные запросы на fs.files. - person Benjamin M; 06.08.2014
comment
ЧАСТЬ 2: Пример. Сохраните изображение с помощью gridFsOperations.store(inputStream, filename, contentType, metadata);. И после этого запросите fs.files, например: mongoTemplate.find(new Query(), MyGridFsFile.class). Он вернет список всех файлов, хранящихся в GridFS (он просматривает аннотацию @Document к MyGridFsFile, чтобы найти нужную коллекцию для запроса). Теперь вы можете позвонить getId() на возвращенный MyGridFsFile. Затем вы можете выполнить GridFSDBFile file = gridFsOperations.findOne(Query.query(Criteria.where("_id").is(id))) и вызвать file.getInputStream(), чтобы получить фактическое содержимое файла. - person Benjamin M; 06.08.2014
comment
ЧАСТЬ 3: Java-драйвер Mongo: ознакомьтесь с исходным кодом класса com.mongodb.gridfs.GridFS. Там вы можете увидеть, как файлы сохраняются. Он использует _bucketName+".files" и _bucketName+".chunks", где _bucketName по умолчанию равно fs. И если вы посмотрите com.mongodb.gridfs.GridFSDBFile исходный код, вы увидите, как он разбивает файл на части и сохраняет их (writeTo методы). И как он передает фрагменты в правильном порядке для создания InputStream (метод getInputStream). То, что там происходит, на довольно низком уровне ;) - person Benjamin M; 06.08.2014
comment
@BenjaminM Я использую GridFS для хранения медиафайлов, я использовал ваши рекомендации, но обнаружил, что это довольно сложно, я новичок в Spring Data. Есть ли шанс, что ты сможешь мне когда-нибудь помочь? - person C_B; 18.06.2016

Вы можете создать объект GridFS с базой данных из вашего MongoTemplate, а затем взаимодействовать с ним:

MongoTemplate mongoTemplate = new MongoTemplate(new Mongo(), "GetTheTemplateFromSomewhere");
GridFS gridFS = new GridFS(mongoTemplate.getDb());

Объект GridFS позволяет создавать, удалять, находить и т. Д.

person Trisha    schedule 24.10.2013