1
votes

at the moment I am developing a backend Server with Play 2 Framework using Scala. I have the following problem:

I save documents like images in MongoDB using the File Handler GridFS. GridFs creates two files:

fs.files, which contains metadata and fs.chunks, which stores the chunks

But I would like to save the images in my own collection. All images should have an database entry like username and comments. I have two ideas how to solve the problem but I am in need of help.

Solution #1:

Use my own collection :

{
   username: String
   comments: Array<String>
   image   : Gridfs 
}

How to get the image in my own collection using GridFS? Is it possible?

Solution #2:

I use the fs.files collection, which contain the metadata and add the entries username and comments. I have tried it out, but it doesn't work.

Who might be able to assist me?

Thanks

1
How large will your image filesizes be? GridFS is a useful approach for storing very large files, but not essential if your images are less than the maximum document size (16MB as at MongoDB 2.6). You can consider storing images directly in a document as binary data (which sounds closer to what you are after with your suggested solutions). - Stennie
I can't say yet. Because I would like to store audio and videofiles, too. That's the reason why I would like to use gridfs. Videofiles will get more than 16MB - masterWN

1 Answers

0
votes

As for Solution #1

If you are using ReactiveMongo, there is an example project, with composite server response, consisting of files and json

https://github.com/sgodbillon/reactivemongo-demo-app/blob/master/app/controllers/Application.scala

 def showEditForm(id: String) = Action.async {
    val objectId = new BSONObjectID(id)
    // get the documents having this id (there will be 0 or 1 result)
    val futureArticle = collection.find(BSONDocument("_id" -> objectId)).one[Article]
    // ... so we get optionally the matching article, if any
    // let's use for-comprehensions to compose futures (see http://doc.akka.io/docs/akka/2.0.3/scala/futures.html#For_Comprehensions for more information)
    for {
      // get a future option of article
      maybeArticle <- futureArticle
      // if there is some article, return a future of result with the article and its attachments
      result <- maybeArticle.map { article =>
        import reactivemongo.api.gridfs.Implicits.DefaultReadFileReader
        // search for the matching attachments
        // find(...).toList returns a future list of documents (here, a future list of ReadFileEntry)
        gridFS.find(BSONDocument("article" -> article.id.get)).collect[List]().map { files =>
          val filesWithId = files.map { file =>
            file.id.asInstanceOf[BSONObjectID].stringify -> file
          }
          Ok(views.html.editArticle(Some(id), Article.form.fill(article), Some(filesWithId)))
        }
      }.getOrElse(Future(NotFound))
    } yield result
  }

You can use it as a reference implementation.

As for Solution #2

You should be able to store additional data in DefaultFileToSave.metadata, and query afterwards mongo with { "metadata.user" : "user"} (Look at Query on MongoDB GridFS metadata (Java))

Another Solution

Keep files & your meta information as independent entities, and manage them independently, it would be easier to extend them in future.

For GridFS upload functionality (https://github.com/ReactiveMongo/Play-ReactiveMongo)

def upload = Action(gridFSBodyParser(gridFS)) { request =>
  // here is the future file!
  val futureFile: Future[ReadFile[BSONValue]] = request.body.files.head.ref
  futureFile.map { file =>
    // do something
    Ok
  }.recover {
    case e: Throwable => InternalServerError(e.getMessage)
  }
}

To expand on previous, in terms of endpoints, as an example

  • /video/:id/file - your GridFS file endpoint
  • /video/:id/meta - your meta information endpoint (what ever you need it to be)
  • /video/:id (optional) - combined file & meta response.