Dear List,
I'm not lazy! I've gone through the mailing list, and various Smalltalk books. There's little information on how to handle nested collections, much less nested MagmaCollections. But I can imagine this would be a fairly common task, especially since object databases are structured in a different way to relational databases. (This also came up on the mailing list a while ago: http://lists.squeakfoundation.org/pipermail/magma/2007-March/ 000598.html)
I've created two example classes: Writer (with 'books' and 'name' instance variables and accessors), and Book (with 'title' instance variable and accessors).
'books' is a MagmaCollection of Book items, contained within Writer (ie. a Writer creates many Books!). This is initialised in Writer:
initialize books := MagmaCollection new. books addIndex: (MaKeywordIndex attribute: #title)
OK, now I create a MagmaCollection called myLibrary and add some example books:
myLibrary := MagmaCollection new. myLibrary addIndex: (MaKeywordIndex attribute: #name).
writer1 := Writer new name: 'Margaret Mitchell'. writer1 books add: (Book new title: 'Gone With the Wind'); add: (Book new title: 'Lost Laysen').
writer2 := Writer new name: 'Kenneth Grahame'. writer2 books add: (Book new title: 'The Wind in the Willows'); add: (Book new title: 'The Reluctant Dragon').
writer3 := Writer new name: 'Anne McCaffrey'. writer3 books add: (Book new title: 'Dragonriders of Pern'); add: (Book new title: 'Crystal Singer').
myLibrary add: writer1; add: writer2; add: writer3.
The problem I'm struggling with is how to query this data structure! I would like to generate collections based on the following queries:
1. All books with titles containing the word 'wind' 2. All writers who have books with titles containing the word 'dragon'
Thanks for any help!
Amir
Hi Amir,
Tyically one refactors the design a bit. This is not neccessary, but MagmaCollections are not light-wight constructs (they support millions of elements and ofer indexing), so it is good practice to avoid hundreds (or many tens) or MagmaCollections.
Here is how I would implement this:
Object Author ( name, library ) "#books is a selector, not an ivar" Book ( author, title )
I would make the root of the repository a Library:
Object Library ( authors, books )
I would initialize Library as:
Library >> initialize authors := MagmaCollection new addIndex: (MagmaStringIndex attribute: #name ); yourself. books := MagmaCollection new addIndex: (MagmaStringIndex attribute: #authorName ); addIndex: (MagmaKeywordIndex attribute: #titleWords ); yourself. !
Ok, so now we implement #authorName and #titleWords to satsify the indices:
Book >> authorName ^ authorName ! Book >> titleWords ^ title findTokens: ' '. !
So, to add authors and books (this is the 'relational' bit :) ):
Library >> addAuthor: anAuthor anAuthor library: self. "NB - used by #addBook: later" authors add: anAuthor ! Author >> addBook: aBook aBook author: self. "for the #authorName index" library books add: aBook "store in the shared books collection" !
- All books with titles containing the word 'wind'
library books books where: [ :b | b titleWords = 'wind' ]
- All writers who have books with titles containing the word 'dragon'
There is no simple query in Magma to perform this classically relational query, but is a common solution:
Author >> = other ^ name = other name ! Author >> hash ^ name hash !
Then:
looners := Set new. (library books books where: [ :b | b titleWords = 'dragon' ]) do: [ :b | looners add: b author ],
Thanks for any help!
Have a look at Lava and Lava-tester for a relational overlay to Magma that provides full SQL query support.
(PS. I am not at my laptop, so this pseudo-code may have the odd syntax error).
Let me know if you need help or advice on other solutions to this problem.
Brent
magma@lists.squeakfoundation.org