Hi Michael, A continuation :)
When I add a relation to a specific type node to indicate what type the node represents then I need to make sure that this node is unique. So the question is should I create the different type nodes before hand, or can I create them on demand? And the concern is consistency, what happens when two requests both want to create this unique type node? Is this possible, or can I guard myself from this? Personally I like my app to create such a node on demand, as this makes moving forward easier (no possibility to screw that up by forgetting to add a type node). -Mark On Fri, Feb 18, 2011 at 12:21 PM, Michael Hunger < michael.hun...@neotechnology.com> wrote: > Feel free to skim it or not, just don't want it to get lost so that no one > else can learn from that or contribute alternative solutions. > > Cheers > > Michael > > 1) All nodes are equal in Neo4j if I am correct, so if I have different > types myself then I just create a node_type property with a text string to > differentiate between f.ex. users and jobs. Is this the correct way to > handle this? > > 2) Complex data structures, I need to store complex data structures in > Neo4j, think about a whole CV like LinkedIn. When I create or update nodes > can U pass-in this complex data structure as a whole? F.ex. below here could > I add a parameter CV that contains a Hash where some values are Hashes > themselves again? Or can should I use JSON as a value? > Neography::Node.create("age" => 31, "name" => "Max") > > 3) I am currently creating my own models (Rails based web app) where the > models themselves are not so much used like in Rails, they are only a nice > way to collect logic in one place. F.ex. I could have Employee.create_new > hash which internally will use neography to create a new employee and return > the created one as a hash. Is this a good way to thank about the problem, or > have other patterns emerged? > > 1) There are several strategies, marking the nodes with certain properties > is one, others are - linking the nodes to a "category" node so that they can > be easily accessed from there, or putting them in a dedicated index for > quick lookup. > > 2) Nodes only have primitive properties right now. To store hashes or more > complex document structures you use other nodes and relationships between > them. That should be quite easy to put in a helper method. > i.e. if the inner property is a hash take its property name and instead of > making a property out of that one, create a relationship with this name to a > node which has the hash keys + values as properties (and recursively so). > > Fortunately it is easy with ruby to just reopen the Node class and add > those convenience methods. I did that as well. (Code below) > > 3) I create my own Domain objects for the Neo4j-Hosting Domain and just > have them get a Neography node as intitializer param, then you can delegate > all store-methods to this node or its node.neo_server and have the other > domain code directly in the object (code also below). I'm also in the > process of exploring this whole remote-rest-store domain modelling, so we > can certainly learn a lot from each other. > > Mark you can still do your uniqueness constraint of the email with the > index. I would have written the same as Jim, put the E-Mail addresses in a > string array field, but be sure to index them not as an array but > individually. > > Regarding your other questions of reading structures. Traversing is crazy > fast in Neo4j. So what you do is not a manual navigation over the > relationships but: > - you get your start node (i.e. the one being the person) from the index or > from another traversal. (you can see that node like a root entity). > > Then you specify a traversal description. I.e. which relationships to > traverse, how deep etc. And then let the neo4j traverser do the work and > have you return all the paths to the nodes that are included in your > traversal - i.e. your whole document == aggregate structure. > > Then in the client you pull those paths into your domain model and have it > ready for processing/displaying whatever. > > For hints for the traversal either look at the code of the previous email > or that a quick look at the neo4j-imdb-app sourcecode at github: > https://github.com/jexp/heroku-neo4j-example > > Cheers > > Michael > > Ok one more question for modeling the data: Say a user can have multiple > e-mail addresses what is the best way to model this? Have a single property > containing a list with addresses or let > email_address be its own entity and create relations between the user and > e-mail_address? The email address will be used to search for a user f.ex. so > I rather have Neo4j being able to > determine if it already exists. > > -Mark > > > There's nothing in Neo4j that determines this one way or another. If email > addresses are first class citizens in your domain, then they should be > nodes. Otherwise make them properties. > > For instane, if you want to be able to assert that two users are actually > the same person because they share an email address, then make the email > address a node. Otherwise it's a property. > > Jim > > I am using e-mail address as a way to select a user, but I didn't think of > it as a first class citizen. A user can have multiple e-mail addresses and > in cases non. The thing I am not sure > about is how to select a user by e-mail address. Can Neo4j have an Array as > property type, using the ReST API and select a node if it the array contains > the filter value? > > I am starting to realize that how I think about my data needs to be a bit > different from f.ex. MongoDB or CouchDB. In many ways I see great > possibilities, but need to get my head around > these fundamental things :) > > -Mark > > > It's possible to index node properties, that gives you effectively what > Mongo does. Arrays are supported, you just pass in a JSON array: > > { "email_addresses" : ["j...@webber.name", "j...@jimwebber.org", " > j...@neotechnology.com"]} > > The question you need to answer is: is there any value in the relationship > between a user and their email address(es)? > > Jim > > Ah cool, that is what I was wondering about how easy Neo could index > properties like an array. Because this is a border case (I might actually > promote e-mail address to a first class citizen for uniqueness check), but > there are other cases where I do not see the need to do this. Then it is > good to know that Neo will handle that easily. > > How much is the ReST API behind the direct Java way? > > -Mark > > Regarding the second - information about those concepts is distributed over > blog posts, wiki entries and mailing list posts. We certainly need more docs > from the users/developers point of > view, e.g. on how to model your domain in a graph. > > What I've just found (but that is by far not enough: > http://wiki.neo4j.org/content/Domain_Modeling_Gallery) > > http://wiki.neo4j.org/content/Design_Guide > > http://stackoverflow.com/questions/1000162/has-anyone-used-graph-based-databases-http-neo4j-org > > http://www.build47.com/posts/neo4j-presentation-at-twitter-headquaters/ > > http://www.slideshare.net/directi/neo4j-and-the-benefits-of-graph-dbs-3-3325734 > > I also would like to discuss how one could map the DDD terms onto a graph > database and where it is fitting and where not. > > Two last points: don't underestimate relationships, they are full first > level citizens and go for traversals rather than manually navigating along > the relationships. > > node_ext.rb > > require 'rubygems' > require 'neography' > > module Neography > class Node > class << self > def create_and_index(data, to_index) > node = Neography::Node.create(data) > return node unless to_index > to_index.each do |index,names| > names.each do | prop | > > node.neo_server.add_node_to_index(index,prop,data[prop],node.neo_id) > end > end > node > end > > def find(index, prop, value) > res = Neography::Rest.new.get_node_index(index,prop,value) > return nil unless res > Neography::Node.load(res.first) > end > end > end > class Rest > def get_type(type) > case type > when :node, "nodes", :nodes, "nodes" > "node" > when :relationship, "relationship", :relationships, > "relationships" > "relationship" > when :path, "path", :paths, "paths" > "path" > when :fullpath, "fullpath", :fullpaths, "fullpaths" > "fullpath" > else > "node" > end > end > end > end > > > domain.rb > require 'node_ext' > > # todo I want to be able to filter for properties with the REST api w/o > reverting to JS > module Gateway > class Provider > def initialize(node) > @node = node > end > > def to_s > "#{@node.name} (#{@node.neo_id})" > end > > class << self > def get(name) > node = Neography::Node.find(:providers,:name,name) > return nil unless node > Provider.new(node) > end > > def add(name) > provider = Provider.get(name) > return provider if provider > node = Neography::Node.create_and_index({:name => name}, :providers > => [:name]) > return nil unless node > Provider.new(node) > end > end > > def plans > @node.outgoing(:active_plan).collect > end > def plan(name) > plans.find { |plan| plan.name == name } > end > > def users > rels.incoming(:account).collect > end > def userFor(account) > users = @node.incoming(:account).filter(" position.lastRelationship() != > null && position.lastRelationship().getProperty('account') == > '#{account}';") > return User.new(users.first) if users && !users.empty? > user = Neography::Node.create_and_index({:name => account, :email => > account}, :users => [:email, :name ]) > @node.neo_server.create_relationship(:account, user, @node, {:account => > account }) > User.new(user) > end > > def new_hash(size = 8) > Digest::SHA1.hexdigest(rand.to_s)[0..size] > end > > def databaseFor(user, plan) > begin > id = new_hash > end while !Node.find(:databases, :id, id) > db = Neography::Node.create_and_index({ > :id => id, :login => new_hash, :password => new_hash, > :state => :creating > }, :databases => [:id]) > > user.outgoing(:active_database) << db > db.outgoin(:has_plan) << plan > > Database.new(db) > end > end > end > > > > > _______________________________________________ > Neo4j mailing list > User@lists.neo4j.org > https://lists.neo4j.org/mailman/listinfo/user > -- Mark Nijhof m: 0047 95 00 99 37 e: mark.nij...@cre8ivethought.com b: cre8ivethought.com/blog/index "Walking on water and developing software from a specification are easy if both are frozen." -- Edward V Berard _______________________________________________ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user