anlek / mongify

Mongify allows you to map your data from a sql database and into a mongodb document database.
http://github.com/anlek/mongify
MIT License
317 stars 82 forks source link

Embed by Reference Support #184

Open paul-uulabs opened 3 years ago

paul-uulabs commented 3 years ago

The current table-level embed_in implementation requires the child to reference the parent by id... but there seems to be no way to embed if the parent references the child...

For example, the following will create a reference to an address (child) within "companies" (parent):

table "addresses" do
    column "address1", :string
    column "address2", :string
    column "suite", :string
    column "city", :string
    column "province", :string
    column "country", :string
    column "phone", :string
    column "zip", :string
    column "created", :datetime
    column "modified", :datetime
    column "id", :key, :as => :integer
end

table "companies" do
    column "title", :string
    column "description", :string
    column "email", :string
    column "website", :string
    column "organizationType", :integer
    column "addressId", :integer, :references => :addresses 
    column "created", :datetime
    column "modified", :datetime
    column "id", :key, :as => :integer
end

... BUT I want to embed the address record in companies... companies has a reference to address only.

Is it possible for Mongify to embed by reference... ?

For example, it would be great if I could do this on the column level:

column "addressId", :integer, :references => :addresses, embed_in=>true

... or maybe there is a way of doing this that I don't understand?

anlek commented 3 years ago

Unfortunately, this is not doable without a bunch of custom code.

You should be able to pull it off, if you use before_save on company, and use the addressId and look up the address manually. To do so, you'd have to read the source code to understand the internals.

paul-uulabs commented 3 years ago

Thank you and that's good to hear. I've looked at the code, but would it be possible to point me in the right direction? I am not sure how to insert a query in a before_save. I'm surprised no one has asked about this.

anlek commented 3 years ago

@paul-uulabs looks like you might be able to use before_save and flip the association. Checkout: https://github.com/anlek/mongify/blob/master/lib/mongify/database/table.rb#L52

paul-uulabs commented 3 years ago

Thanks @anlek,

I managed to use before_save to embed address references in companies, like I want... BUT the company record is still embedded into addresses in the end... so I end up with address>company>address ... if I could update the company table and stop the embed, I'd have what I want (company>address)... I am not sure if that is what you meant by "flip the association" ..? I cannot flip the tables completely (i.e.: rename "address" tables as "company", embed, and finally move the fields around) because addresses are referenced by several tables, not just companies... I don't know if it is possible to access the table object in before_save to embed the address record into the company collection, etc..?

This is what I have...?

table "addresses" do
    column "title", :string
    column "address1", :string, :rename_to => 'addressStreet' 
    column "address2", :string, :rename_to => 'addressSecondary'
    column "suite", :string
    column "city", :string
    column "province", :string
    column "country", :string
    column "phone", :string
    column "zip", :string
    column "addressType", :integer
    column "description", :string
    column "email", :string
    column "created", :datetime
    column "modified", :datetime
    column "id", :key, :as => :integer
end

table "companies", :embed_in => :addresses, :on => :addressId do
    column "title", :string
    column "description", :string
    column "email", :string
    column "website", :string
    column "organizationType", :integer
    column "addressId", :integer, :references => :addresses 
    column "created", :datetime
    column "modified", :datetime
    column "id", :key, :as => :integer
    before_save do |row, parent_row|
        row.address = {}
        if parent_row.title
            row.address["title"] = parent_row.title
            row.address["address1"] = parent_row.addressStreet
            row.address["address2"] = parent_row.addressSecondary
            row.address["suite"] = parent_row.suite
            row.address["city"] = parent_row.city
            row.address["province"] = parent_row.province
            row.address["country"] = parent_row.country
            row.address["phone"] = parent_row.phone
            row.address["zip"] = parent_row.zip
            row.address["addressType"] = parent_row.addressType
            row.address["description"] = parent_row.description
            row.address["email"] = parent_row.email
            row.address["created"] = parent_row.created
            row.address["modified"] = parent_row.modified
        end
    end
end

Also, I found a limitation in before_save... notice that my properties in addresses include "address1" and "address2"... Mongify strips out numeric characters in fields in data_row.rb so I could not access them in before_save unless I renamed them.