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

Reply via email to