Hi Esteban, It seems that I mistook the question for something easy enough for me to answer! Unfortunately, I don't have any knowledge of Voyage+MongoDB so can't really give the proper answer. James On Aug 30, 2013, at 11:13 AM, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Hi James,
Thanks for your response. You are right, the Pattern is quite common, if not ubiquous in all systems.
My particular question is related with Voyage+MongoDB, and also could apply to Magritte (given the fact Voyage "inherits" its descriptions model).
I sucessfully implemented this pattern with ORMs using an intermediary table for the relation, or even reifying the relation as a first class object. I also used the #select: technique to avoid duplication of "responsibility" and caching at one side of the relation. But I always did it "in memory" with no mapping et all, just plain old smalltalk objects (POSO?) and using ORM solutions.
What I need to know now is: 1) How to do this with voyage+MongoDB 2) I want to have a two way relation, it is both members and groups have a collection (members know their groups and viceversa). This requires additional maintenance, but with a higher performance, and doesn't require me to load all groups if I'm just materializing one member.
Regards!
Esteban A. Maringolo
2013/8/30 James Foster <Smalltalk@jgfoster.net>:
Hi Esteban,
What you have described is quite common and there are a variety of ways of designing this sort of object model. If you were dealing with a relational database, then you would have a Group table, a Member table, and a Membership table. The Membership table would have one row for each member/group pair and the member ID and group ID would be the primary columns (perhaps with other things like date joined, date expired, etc.). With an index on the member ID and group ID, one could quickly find all the groups for a member and all the members for a group, and each piece of data would exist in only one place ("normalized"). One could take a similar approach with objects, having three collections containing Groups, Members, and Memberships respectively. You could have an accessor in Group that returned members based on a select from the Memberships collection and an accessor in Member that returned groups based on a select from the Memberships collection.
Alternatively, if you wanted to avoid the #'select:' call in one or both lookups, you can cache the respective subcollections in Group and/or Member and drop the Memberships collection. If you cache in only one place (e.g., each Group has a collection of Members), then you can add a method in Member that does a #'select:' of Groups where a Group has the Member. If you cache in both places then your getters/setters in each can update the other (with the understanding that you are duplicating data to get performance efficiency).
Again, this problem is very common. Consider students in classes, persons with addresses, persons with hobbies, etc. Your choices are basically (1) three collections, no duplicates, select for both queries; (2) two collections, no duplicates, cache for one query, select for the other query; and (3) two collections, caches for each query. Which is preferable depends on your typical sizes and lookup patterns. If performance is not an issue, then start with whatever is simplest for you to code. I lean toward the three collections with the lookup penalty (GemStone's ability to index collections makes this approach very efficient), but if most of your lookups are from one side or the other and scanning the full collection is slow, then cache in one or both places.
If you have a composite, the analysis is similar since Smalltalk does not require static typing of variables. You just need to take care that your accessors can give back the expected objects.
James
On Aug 29, 2013, at 6:12 PM, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Hi all,
Let's say I have a class Group and a class Member.
aGroup has many members. and aMember can belong to many groups.
What is the "proper" voyageDescription for those one to many relations?
Should I do something extra?
Everytime I add a member to the group, both the member and the group get their references updated. Now when I add a member to a group and save it, I also save the member. Is there another way to avoid this?
Any recommended practice for this?
Next level question: What if it gets composite? it is... a Group has other Groups as members :)
Regards!
Esteban A. Maringolo