mongoid / mongoid-grid_fs

A pure Mongoid/Moped implementation of the MongoDB GridFS specification.
Other
83 stars 50 forks source link

Cannot specify which database to store chunks and files in #53

Closed maxjacobson closed 8 years ago

maxjacobson commented 9 years ago

I believe this is the case.

I'm using this sweet gem via carrierwave-mongoid and I've run up into an interesting snag; I'd like to store some files in one database, and others in another database, ala this Mongoid syntax:

class Banana
  include Mongoid::Document
  store_in database: 'fruits'
end

I'm looking through the code, and it doesn't seem like this is currently possible. I'd love to be wrong :smile: but I'd also love to try and add this functionality if you agree it might be useful to people. What do you think?

rmm5t commented 9 years ago

@maxjacobson

As you can see here, the Chunk and File stores are represented by Mongoid documents themselves: https://github.com/ahoward/mongoid-grid_fs/blob/master/lib/mongoid/grid_fs.rb#L253

So, you could reopen these classes (Mongoid::GridFs::Fs::File and Mongoid::GridFs::Fs::Chunk) and assign them to a different database.

However, I'm not entirely sure about support for storing some files in one database and other files in another. Do you want to do this on a per record basis or a per parent-model basis? Either way, @ahoward might have to chime in here to shed more light on the possibilities.

maxjacobson commented 9 years ago

Hey @rmm5t thanks for thinking it through and explaining!

I think "per parent-model basis" is more what we were thinking, if I'm understanding that correctly.

I'll take the example from the carrierwave-mongoid readme:

class User
  include Mongoid::Document
  mount_uploader :avatar, AvatarUploader
  store_in :database => 'some_not_default_database'
end

class AvatarUploader < CarrierWave::Uploader::Base
  storage :grid_fs
end

u = User.new
u.avatar = File.open('somewhere')
u.save!

Then when we go to mongo shell we see this:

use some_not_default_database
db.users.count(); //=> 1
db.fs.files.count(); //=> 0
db.fs.chunks.count(); //=> 0

use default
db.users.count(); //=> 0
db.fs.files.count(); //=> 1
db.fs.chunks.count(); //=> 1+

Which totally makes sense given the way carrierwave-mongoid and mongoid-grid_fs work, but the behavior we were kind of hoping it would have was that it would group the files with the parent collection in the non-default database.

Of course, this library isn't aware of that, because that whole mounting thing is done in carrierwave-mongoid and carrierwave, not here...

We could get away with putting all GridFS files/chunks in one database, but in that case we'd like to be able to make it a non-default database. Which we can do by opening up Mongoid::GridFS::Fs::File and Mongoid::GridFS::Fs::Chunk, as you said. That's probably what we'll do.

It seems like we should be able to use the "namespace" idea to group our files/chunks by that parent relationship, maybe, but it's not really clear (to me) how we might do that. Is the fs namespace designed to be overriden? If so, is it designed to be overriden so you can have multiple files and chunks collections? Or just so you can rename the one files collection and the one chunks collection?

Thanks for your time!

ahoward commented 8 years ago

hai @maxjacobson -

i wrote the namespace idea - straight off of the spec.

yes. you should be able to do what you are after

1st, the namespace concept isn't really about dbs, it is about scoping collection names

'like.this'

specifically nest all the shit under 'like', or, 'namespace'

having said that the scoping code building fully fledged mongoid models (a major goal of the libraray) and those respond to all the normal mongoid stuff (whatever version you may be running). thus. you should be able to do something like:


ns = GridFs.namespace_for(:ns)

Chunk = ns.chunk_model

File = ns.file_model

File.class_eval{ store_in database: "teh_database" }

Chunk.class_eval{ store_in_database: "teh_database" }

specifically - the driver is *dumb* an returns *normal* mongoid classes.  on those classes, you can do what you like.
maxjacobson commented 8 years ago

@ahoward hey, thanks so much for digging into this! I'm going to close this issue because I think we resolved our problem with some other workaround, and because your code sample there looks like it should help anyone out who stumbles on this in the future. Thanks!