How to rename MongoDb collections with Mongoc.jl

I am using Mongoc.jl to work with MongoDb. I need to be able to rename collections. In Python - using PyMongo - it can be done with database["someName"].rename["newName]. But with Mongoc I can’t find any functionality to accomplish this. I spent hours searching on the internet, but I found no solution that worked (at least not for me…). Can anyone help me with this?

Seems like Mongoc.jl does not provide a binding in Mongoc.jl/c_api.jl at master · felipenoris/Mongoc.jl · GitHub to call the mongoc_collection_rename function from libmongoc: mongoc_collection_rename() — libmongoc 1.23.4

You could try hacking that in yourself, though.
I think the src/c_api.jl in Mongoc.jl has lots of similar functions which you could use as templates to get started.

And if you succeed, it could perhaps also be merged into Mongoc.jl?

As for my Julia experience, I don’t feel confident enough to do such a hack myself (yet?). A second option I tried is to use Pycall with Pymongo, but of all libraries I can’t get Pymongo to work in Julia… And a third solution might be to copy collections and give the copies the intended target names.The first option - the rename - would be the best though, but alas…

I took a brief look and came up with this bit:

using Mongoc


function mongoc_collection_rename_with_opts(collection_handle::Ptr{Cvoid},
    new_db::AbstractString, new_name::AbstractString,
    drop_target_before_rename::Bool, bson_opts::Ptr{Cvoid},
    bson_error_ref::Ref{Mongoc.BSONError})

  ccall((:mongoc_collection_rename_with_opts, Mongoc.libmongoc), Bool,
        (Ptr{Cvoid}, Cstring, Cstring, Bool, Ptr{Cvoid}, Ref{Mongoc.BSONError}),
        collection_handle, new_db, new_name, drop_target_before_rename, bson_opts, bson_error_ref)
end


function rename!(collection::Mongoc.Collection, new_db::AbstractString, new_name::AbstractString,
    drop_target_before_rename::Bool, options::Union{Nothing,Mongoc.BSON}=nothing)

  err_ref = Ref{Mongoc.BSONError}()
  options_handle = options === nothing ? C_NULL : options.handle
  ok = mongoc_collection_rename_with_opts(collection.handle, new_db, new_name, drop_target_before_rename,
                                         options_handle, err_ref)
  if !ok
    throw(err_ref[])
  end
end

Unfortunately, installing MongoDB on my Fedora machine is more difficult :laughing:, so I couldn’t test it.
I might try with my PC at work when I find time for it…

I tried it out like this:

client = Mongoc.Client()
database = client["DB_2"]
...
rename!(database[cur_coll_name], "DB_2", new_coll_name, false)

In the function rename! the following line

ok = mongo_collection_rename_with_opts(collection, new_db, new_name, drop_target_before_rename,
                                         options_handle, err_ref)

gives this error message:

MethodError: no method matching mongo_collection_rename_with_opts(::Mongoc.Collection, ::String, ::String, ::Bool, ::Ptr{Nothing}, ::Base.RefValue{Mongoc.BSONError})

Closest candidates are:
  mongo_collection_rename_with_opts(!Matched::Ptr{Nothing}, ::AbstractString, ::AbstractString, ::Bool, ::Ptr{Nothing}, ::Ref{Mongoc.BSONError})

Something with the parameters?

Sorry, my bad. I think we need to call mongo_collection_rename_with_opts with collection.handle and not collection.
I update my answer.


EDIT: I also misspelled the C functions, they all start with mongoc_ and not mongo_. I update that as well in the above.

Yes, it works, beautiful! I only had to make one little correction in the line

options_handle = options == nothing ? C_NULL : options.handle

According to the code checker options == nothing must be options === nothing (the strict way).

I have both functions now placed with my ‘other code’, which works fine but is not so elegant. Can I put them in src/c_api.jl in Mongoc.jl just like that, or does that imply extra steps (except for being careful with possible updates of Mongoc.jl)? And what should be done to give others the opportunity to use these functions as well (that part is new for me)?

But anyway, it works and I am very happy with it! Thank you for your help!

1 Like

That bit I also copied from Mongoc.jl to be consistent with the library, but indeed, it should be ===.

I have both functions now placed with my ‘other code’, which works fine but is not so elegant. Can I put them in src/c_api.jl in Mongoc.jl just like that, or does that imply extra steps (except for being careful with possible updates of Mongoc.jl)?

In theory, it should work if you put it in ~/.julia/packages/Mongoc/.../src/c_api.jl, but I would recommend against it, because you will have to “reapply” that change whenever you update the Mongoc package to a newer verison (that’s why there are folders with cryptic names inside ~/.julia/packages/Mongoc/).
For the moment I would just keep the code in your package in a separate file, maybe call it mongoc_utils.jl and then include("mongoc_utils.jl") it where you need it.

And what should be done to give others the opportunity to use these functions as well (that part is new for me)?

This requires a Github account, which I assume you already have.
Then go to GitHub - felipenoris/Mongoc.jl: MongoDB driver for the Julia Language, click Fork on the top right and then git clone your fork of the package. Then add the code to src/c_api.jl and src/collections.jl and commit and push the changes, again to your fork. Once that is done, go back to the Mongoc.jl Github page, then Pull requests and New Pull request, then fill in some words (perhaps link to this page) and submit.
The project seems active, so someone will come back to you with comments and suggestions to make it work with the package before they merge it.

Good luck!