How to create a relation between 2 documents in MongoDB? - ruby-on-rails

I have a Ruby on Rails application that usually communicates with MongoDB through the Mongoid gem, but for performance reasons I need to insert documents directly into MongoDB like this:
Order.collection.insert(Array.new << {order_id: order_id, mail_address: mail_address}) # this creates the document, but does not return anything useful that can be referenced: {"n"=>0, "connectionId"=>53675, "wtime"=>0, "err"=>nil, "ok"=>1.0}
Customer.collection.insert(Array.new << {mail_address: mail_address})
I have defined a relationshop where a Customer has many Orders, so if I used Mongoid I could create the relation with customer.orders << order.
But how do I create the relation when I'm not using Mongoid?

None of Moped's insert methods return anything terribly useful to you so your documents are getting normal ObjectId's in their _id but you have no easy way of knowing what they are. You're on the right track by trying to assign your own _ids but you don't have to use Strings, you can simply say Moped::BSON::ObjectId.new to generate a new _id. Assuming that your Orders have a customer_id which points at the Customer, you could:
customer_id = Moped::BSON::ObjectId.new
Customer.collection.insert(_id: customer_id, mail_address: mail_address)
Order.collection.insert(customer_id: customer_id, ...)
Don't be afraid to poke around inside MongoDB using the mongo shell to see how things are structured internally. All the helpful relations and embedding conveniences that Mongoid provides are nice but you still need to know what they're doing to your database.

Related

One-to-one relationship with variable case string keys in Rails

Working with legacy database here, can't change the tables.
Have two tables. Lets say User and Admin. They both have user_id which is a string, and the case varies between the tables. I can pull out records by doing donwcase but its a manual query with no fancy ActiveRecord assosiation goods
How can I connect the two models?
I know that you can supply lambda to has_one and belongs_to, except it is used to narrow down the search, not to replace the AR generated one.
I am considering creating views on those tables and lowering the user_id in them. That could work if I dont figure out how to get this going

ActiveRecord relations inside serialized hash - best way to handle the join table?

I have a weird situation. I have two models ("object" and "asset") and a polymorphic join table (things other than objects can relate to assets). The "object" has a serialized hash, where some of the values are ID numbers (foreign keys, although not marked as such in the db) for "assets", and I would like to properly track which "assets' are being used in which "objects" in that join table, and I'm not sure of the best way to go about it.
The main purpose of this set up is to allow us to list all the objects, etc, that use a given asset. Many of the other things that use assets also have such a serialized hash situation.
What I think I need to do is just update the entries in the join table based on a simple scan of the hash for the ID values, and, from there, just treat it like any many-to-one situation.
But, I also wonder if there's a better way to go about it?
(I can't really change the architecture - the serialized hash is actually for use in a completely different codebase, and while I technically don't have to use the join table, I'd prefer to not add another way to do the book-keeping on this kind of relationship.)
PS - Rails on Postgres.

Can I have a one way HABTM relationship?

Say I have the model Item which has one Foo and many Bars.
Foo and Bar can be used as parameters when searching for Items and so Items can be searched like so:
www.example.com/search?foo=foovalue&bar[]=barvalue1&bar[]=barvalue2
I need to generate a Query object that is able to save these search parameters. I need the following relationships:
Query needs to access one Foo and many Bars.
One Foo can be accessed by many different Queries.
One Bar can be accessed by many different Queries.
Neither Bar nor Foo need to know anything about Query.
I have this relationship set up currently like so:
class Query < ActiveRecord::Base
belongs_to :foo
has_and_belongs_to_many :bars
...
end
Query also has a method which returns a hash like this: { foo: 'foovalue', bars: [ 'barvalue1', 'barvalue2' } which easily allows me to pass these values into a url helper and generate the search query.
This all works fine.
My question is whether this is the best way to set up this relationship. I haven't seen any other examples of one-way HABTM relationships so I think I may be doing something wrong here.
Is this an acceptable use of HABTM?
Functionally yes, but semantically no. Using HABTM in a "one-sided" fashion will achieve exactly what you want. The name HABTM does unfortunately insinuate a reciprocal relationship that isn't always the case. Similarly, belongs_to :foo makes little intuitive sense here.
Don't get caught up in the semantics of HABTM and the other association, instead just consider where your IDs need to sit in order to query the data appropriately and efficiently. Remember, efficiency considerations should above all account for your productivity.
I'll take the liberty to create a more concrete example than your foos and bars... say we have an engine that allows us to query whether certain ducks are present in a given pond, and we want to keep track of these queries.
Possibilities
You have three choices for storing the ducks in your Query records:
Join table
Native array of duck ids
Serialized array of duck ids
You've answered the join table use case yourself, and if it's true that "neither [Duck] nor [Pond] need to know anything about Query", using one-sided associations should cause you no problems. All you need to do is create a ducks_queries table and ActiveRecord will provide the rest. You could even opt to use has_many :through relationship if you need to do anything fancy.
At times arrays are more convenient than using join tables. You could store the data as a serialized integer array and add handlers for accessing the data similar to the following:
class Query
serialize :duck_ids
def ducks
transaction do
Duck.where(id: duck_ids)
end
end
end
If you have native array support in your database, you can do the same from within your DB. similar.
With Postgres' native array support, you could make a query as follows:
SELECT * FROM ducks WHERE id=ANY(
(SELECT duck_ids FROM queries WHERE id=1 LIMIT 1)::int[]
)
You can play with the above example on SQL Fiddle
Trade Offs
Join table:
Pros: Convention over configuration; You get all the Rails goodies (e.g. query.bars, query.bars=, query.bars.where()) out of the box
Cons: You've added complexity to your data layer (i.e. another table, more dense queries); makes little intuitive sense
Native array:
Pros: Semantically nice; you get all the DB's array-related goodies out of the box; potentially more performant
Cons: You'll have to roll your own Ruby/SQL or use an ActiveRecord extension such as postgres_ext; not DB agnostic; goodbye Rails goodies
Serialized array:
Pros: Semantically nice; DB agnostic
Cons: You'll have to roll your own Ruby; you'll loose the ability to make certain queries directly through your DB; serialization is icky; goodbye Rails goodies
At the end of the day, your use case makes all the difference. That aside, I'd say you should stick with your "one-sided" HABTM implementation: you'll lose a lot of Rails-given gifts otherwise.

Loading all the data but not from all the tables

I watched this rails cast http://railscasts.com/episodes/22-eager-loading but still I have some confusions about what is the best way of writing an efficient GET REST service for a scenario like this:
Let's say we have an Organization table and there are like twenty other tables that there is a belongs_to and has_many relations between them. (so all those tables have a organization_id field).
Now I want to write a GET and INDEX request in form of a Rails REST service that based on the organization id being passed to the request in URL, it can go and read those tables and fill the JSON BUT NOT for ALL of those table, only for a few of them, for example let's say for a Patients, Orders and Visits table, not all of those twenty tables.
So still I have trouble with getting my head around how to write such a
.find( :all )
sort of query ?
Can someone show some example so I can understand how to do this sort of queries?
You can include all of those tables in one SQL query:
#organization = Organization.includes(:patients, :orders, :visits).find(1)
Now when you do something like:
#organization.patients
It will load the patients in-memory, since it already fetched them in the original query. Without includes, #organization.patients would trigger another database query. This is why it's called "eager loading", because you are loading the patients of the organization before you actually reference them (eagerly), because you know you will need that data later.
You can use includes anytime, whether using all or not. Personally I find it to be more explicit and clear when I chain the includes method onto the model, instead of including it as some sort of hash option (as in the Railscast episode).

MongoDB, Grails, and relationships

I was curious about how the MongoDB plugin for Grails would handle relationships. In order to test this I made a very simple application with two domain classes:
Authors have two fields: String firstName and String lastName
Books have two fields: String title and Author author
After setting up MongoDB and Grails I made some Authors and Books and took a peek using the MongoDB interactive shell. What I found is that the relationships were being handled the same way they would be handled in a relational database: references to other objects' id fields.
So now for the questions:
In order for GORM to pull this off, does it need a separate connection to retrieve each document?
If yes, wouldn't this be better off in a relational database such as PostgreSQL or MySQL?
If the answer to the above two questions is indeed 'yes,' then is there a better way to manage relationships in a document database such as MongoDB? I realize MongoDB isn't supposed to be relational, but there are some things that I don't see how to get around relationships without duplicating data (thereby making update nightmares).
Edit: I also just noticed that grails is not sorting properly on the 'id' property of my authors. Does this have to do with using MongoDB? In the shell I can see that the _id property of all the documents made by Grails is of the datatype NumberLong.
I realize MongoDB isn't supposed to be relational, but there are some things that I don't see how to get around relationships without duplicating data
Then don't sweat it. MongoDB is not anti-relational, it's document-oriented.
In this case, Books and Authors are two top-level objects. It's not reasonable to nest either of them, they are both core entities in their own right.
In the case of each Book having only one Author (N:1), it's completely reasonable for the Book to contain a "Reference To" the Author. Sure you'll have to do two queries. But is that terribly different from doing a join query? The join query still has to do two index look-ups and two data lookups. So you're not really costing yourself anything here.
In the case of each Book supporting multiple Authors (M:N), then you have several options based on your needs.
I don't like to think of MongoDB as "not relational", I think it's cleaner to think of MongoDB as query-optimized.
I also just noticed that grails is not sorting properly on the 'id' property of my authors...
I would check directly with the Grails author. Sounds like they may be storing "strings" instead of actual ObjectIds (or MongoIDs). While not critical this may be a bug.
In regards to the id property, the documentation now shows that you can put a declaration of ObjectId id or String id in your domain class in order to not use the default GORM implementation of using an iterating long. Simply declare the field in your class, and the plugin will take care of the rest.

Resources